sign

package
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2025 License: MIT Imports: 7 Imported by: 4

README

Blockchain-Agnostic Signing Library

A blockchain-agnostic library for cryptographic operations.

Core Design

This library separates generic interfaces from specific blockchain implementations.

Features

  • Blockchain-Agnostic Interfaces: Defines a standard set of interfaces for cryptographic operations.
  • EVM Implementation: Includes a ready-to-use implementation for Ethereum and other EVM-compatible chains.
  • Easily Extensible: Simple to add support for new blockchains like Solana, Bitcoin, etc.
  • Type-Safe: Provides distinct types for Address, Signature, PublicKey, and PrivateKey.

Usage

See the Go package documentation and examples by running:

go doc -all [github.com/erc7824/nitrolite/clearnode/pkg/sign](https://github.com/erc7824/nitrolite/clearnode/pkg/sign)

Documentation

Overview

Package sign provides blockchain-agnostic cryptographic signing interfaces.

This package defines core interfaces for digital signatures that can be implemented by various blockchain ecosystems while maintaining a consistent API for signing operations.

The primary interfaces are:

  • Signer: Core interface for cryptographic signing operations
  • PublicKey: Interface for public key operations
  • Address: Interface for blockchain addresses
  • AddressRecoverer: Optional interface for signature-based address recovery

Security Design

This package follows security best practices by:

  • Never exposing private key material through interfaces
  • Providing only necessary operations (signing and public key access)
  • Supporting hardware security modules (HSM) and key management services (KMS)
  • Preventing accidental private key leakage in logs or debugging

Usage

// Create a new Ethereum signer from a hex-encoded private key
signer, err := sign.NewEthereumSigner(privateKeyHex)
if err != nil {
    log.Fatal(err)
}

// Sign a message (provide hash, not raw message)
message := []byte("hello world")
hash := ethcrypto.Keccak256Hash(message)
signature, err := signer.Sign(hash.Bytes())
if err != nil {
    log.Fatal(err)
}

// Get the address
address := signer.PublicKey().Address()
fmt.Println("Address:", address.String())

Package sign provides mock implementations for testing signature operations.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

type Address interface {
	fmt.Stringer // All addresses must have a string representation.

	// Equals returns true if this address equals the other address.
	Equals(other Address) bool
}

Address is an interface for a blockchain-specific address.

func RecoverAddressFromHash

func RecoverAddressFromHash(hash []byte, sig Signature) (Address, error)

RecoverAddressFromHash recovers an address from a signature using a pre-computed hash.

Example

ExampleRecoverAddressFromHash demonstrates Ethereum-specific address recovery.

package main

import (
	"fmt"
	"log"

	"github.com/erc7824/nitrolite/clearnode/pkg/sign"
	ethcrypto "github.com/ethereum/go-ethereum/crypto"
)

func main() {
	// Example message for standard recovery
	message := []byte("hello world")

	// Create a signature using our signer
	pkHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
	signer, err := sign.NewEthereumSigner(pkHex)
	if err != nil {
		log.Fatal(err)
	}

	hash := ethcrypto.Keccak256Hash(message)
	signature, err := signer.Sign(hash.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	// Call the function directly from the `sign` package for hash recovery
	recoveredAddr, err := sign.RecoverAddressFromHash(hash.Bytes(), signature)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	// Verify it matches the signer's address
	signerAddr := signer.PublicKey().Address()
	fmt.Printf("Addresses match: %t\n", recoveredAddr.Equals(signerAddr))
}
Output:

Addresses match: true

type AddressRecoverer

type AddressRecoverer interface {
	RecoverAddress(message []byte, signature Signature) (Address, error)
}

AddressRecoverer is an interface for recovering addresses from signatures.

func NewAddressRecoverer

func NewAddressRecoverer(sigType Type) (AddressRecoverer, error)

NewAddressRecoverer creates an appropriate AddressRecoverer based on the signature algorithm.

func NewAddressRecovererFromSignature

func NewAddressRecovererFromSignature(signature Signature) (AddressRecoverer, error)

NewAddressRecovererFromSignature creates an AddressRecoverer based on signature algorithm detection.

type EthereumAddress

type EthereumAddress struct{ common.Address }

EthereumAddress implements the Address interface for Ethereum.

func NewEthereumAddress

func NewEthereumAddress(addr common.Address) EthereumAddress

NewEthereumAddress creates a new Ethereum address from a common.Address.

func NewEthereumAddressFromHex

func NewEthereumAddressFromHex(hexAddr string) EthereumAddress

NewEthereumAddressFromHex creates a new Ethereum address from a hex string.

func (EthereumAddress) Equals

func (a EthereumAddress) Equals(other Address) bool

Equals returns true if this address equals the other address.

func (EthereumAddress) String

func (a EthereumAddress) String() string

type EthereumAddressRecoverer

type EthereumAddressRecoverer struct{}

EthereumAddressRecoverer implements the AddressRecoverer interface for Ethereum.

Example

ExampleEthereumAddressRecoverer demonstrates using the generic AddressRecoverer interface.

package main

import (
	"fmt"
	"log"

	"github.com/erc7824/nitrolite/clearnode/pkg/sign"
	ethcrypto "github.com/ethereum/go-ethereum/crypto"
)

func main() {
	message := []byte("hello world")

	// Create a signer
	pkHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
	signer, err := sign.NewEthereumSigner(pkHex)
	if err != nil {
		log.Fatal(err)
	}

	// Sign the message (note: Ethereum signers expect a hash)
	hash := ethcrypto.Keccak256Hash(message)
	signature, err := signer.Sign(hash.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	// Use the dedicated AddressRecoverer implementation
	var recoverer sign.AddressRecoverer = &sign.EthereumAddressRecoverer{}
	// The recoverer implementation will hash the raw message internally
	recoveredAddr, err := recoverer.RecoverAddress(message, signature)
	if err != nil {
		log.Fatal(err)
	}

	signerAddr := signer.PublicKey().Address()
	fmt.Printf("Generic recovery works: %t\n", recoveredAddr.Equals(signerAddr))
}
Output:

Generic recovery works: true

func (*EthereumAddressRecoverer) RecoverAddress

func (r *EthereumAddressRecoverer) RecoverAddress(message []byte, signature Signature) (Address, error)

RecoverAddress implements the AddressRecoverer interface.

type EthereumPublicKey

type EthereumPublicKey struct{ *ecdsa.PublicKey }

EthereumPublicKey implements the PublicKey interface for Ethereum.

func NewEthereumPublicKey

func NewEthereumPublicKey(pub *ecdsa.PublicKey) EthereumPublicKey

NewEthereumPublicKey creates a new Ethereum public key from an ECDSA public key.

func NewEthereumPublicKeyFromBytes

func NewEthereumPublicKeyFromBytes(pubBytes []byte) (EthereumPublicKey, error)

NewEthereumPublicKeyFromBytes creates a new Ethereum public key from raw bytes.

func (EthereumPublicKey) Address

func (p EthereumPublicKey) Address() Address

func (EthereumPublicKey) Bytes

func (p EthereumPublicKey) Bytes() []byte

type EthereumSigner

type EthereumSigner struct {
	// contains filtered or unexported fields
}

EthereumSigner is the Ethereum implementation of the Signer interface.

func (*EthereumSigner) PublicKey

func (s *EthereumSigner) PublicKey() PublicKey

func (*EthereumSigner) Sign

func (s *EthereumSigner) Sign(hash []byte) (Signature, error)

Sign expects the input data to be a hash (e.g., Keccak256 hash).

type MockAddress added in v0.4.0

type MockAddress struct {
	// contains filtered or unexported fields
}

MockAddress is a mock implementation of the Address interface for testing. It uses a simple string ID as the address representation.

func NewMockAddress added in v0.4.0

func NewMockAddress(id string) *MockAddress

NewMockAddress creates a new MockAddress with the given ID.

func (*MockAddress) Equals added in v0.4.0

func (m *MockAddress) Equals(other Address) bool

Equals compares this address with another by comparing their string representations.

func (*MockAddress) String added in v0.4.0

func (m *MockAddress) String() string

String returns the ID as the string representation of the address.

type MockPublicKey added in v0.4.0

type MockPublicKey struct {
	// contains filtered or unexported fields
}

MockPublicKey is a mock implementation of the PublicKey interface for testing. It stores an ID string that is used as both the key data and address.

func NewMockPublicKey added in v0.4.0

func NewMockPublicKey(id string) *MockPublicKey

NewMockPublicKey creates a new MockPublicKey with the given ID.

func (*MockPublicKey) Address added in v0.4.0

func (m *MockPublicKey) Address() Address

Address returns a mock address based on the public key's ID.

func (*MockPublicKey) Bytes added in v0.4.0

func (m *MockPublicKey) Bytes() []byte

Bytes returns the ID as a byte slice.

type MockSigner added in v0.4.0

type MockSigner struct {
	// contains filtered or unexported fields
}

MockSigner is a mock implementation of the Signer interface for testing purposes. It generates predictable signatures by appending a suffix to the data.

func NewMockSigner added in v0.4.0

func NewMockSigner(id string) *MockSigner

NewMockSigner creates a new MockSigner with the given ID. The ID is used to create the underlying mock public key.

func (*MockSigner) PublicKey added in v0.4.0

func (m *MockSigner) PublicKey() PublicKey

PublicKey returns the mock public key associated with this signer.

func (*MockSigner) Sign added in v0.4.0

func (m *MockSigner) Sign(data []byte) (Signature, error)

Sign generates a mock signature by appending a suffix containing the signer's address. This creates predictable signatures useful for testing.

type PublicKey

type PublicKey interface {
	Address() Address
	Bytes() []byte
}

PublicKey is an interface for a blockchain-agnostic public key.

type Signature

type Signature []byte

Signature is a generic byte slice representing a cryptographic signature.

func (Signature) MarshalJSON

func (s Signature) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface, encoding the signature as a hex string.

func (Signature) String

func (s Signature) String() string

String implements the fmt.Stringer interface

Example

ExampleSignature_String demonstrates the String method of Signature.

package main

import (
	"fmt"

	"github.com/erc7824/nitrolite/clearnode/pkg/sign"
)

func main() {
	sig := sign.Signature([]byte{0x01, 0x02, 0x03, 0x04})
	fmt.Println(sig.String())
}
Output:

0x01020304

func (Signature) Type

func (s Signature) Type() Type

Type returns the signature type for this signature based on its length and structure.

func (*Signature) UnmarshalJSON

func (s *Signature) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

type Signer

type Signer interface {
	PublicKey() PublicKey                // Public key associated with this signer.
	Sign(data []byte) (Signature, error) // Sign generates a signature for the given data.

}

Signer is an interface for a blockchain-agnostic signer.

func NewEthereumSigner

func NewEthereumSigner(privateKeyHex string) (Signer, error)

NewEthereumSigner creates a new Ethereum signer from a hex-encoded private key.

Example

ExampleNewEthereumSigner demonstrates creating an Ethereum signer and signing a message.

package main

import (
	"fmt"
	"log"

	"github.com/erc7824/nitrolite/clearnode/pkg/sign"
	ethcrypto "github.com/ethereum/go-ethereum/crypto"
)

func main() {
	pkHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" // Example private key

	// Create a new Ethereum signer. It returns the generic sign.Signer interface.
	signer, err := sign.NewEthereumSigner(pkHex)
	if err != nil {
		log.Fatal(err)
	}

	// You can now use the signer for generic operations.
	fmt.Println("Address:", signer.PublicKey().Address())

	message := []byte("hello world")
	hash := ethcrypto.Keccak256Hash(message)
	signature, err := signer.Sign(hash.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Signature length:", len(signature))
}
Output:

Address: 0x1Be31A94361a391bBaFB2a4CCd704F57dc04d4bb
Signature length: 65

type Type

type Type uint8

Type represents the signature type/platform used for signatures.

const (
	TypeEthereum Type = iota
	TypeUnknown       = 255
)

func (Type) String

func (t Type) String() string

String returns the string representation of the algorithm.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL