sign

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 7 Imported by: 0

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/layer-3/nitrolite/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.NewEthereumRawSigner(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

func ComputeEthereumSignedMessageHash

func ComputeEthereumSignedMessageHash(message []byte) []byte

ComputeEthereumSignedMessageHash accepts an arbitrary message, prepends a known message, and hashes the result using keccak256. The known message added to the input before hashing is "\x19Ethereum Signed Message:\n" + len(message).

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"

	ethcrypto "github.com/ethereum/go-ethereum/crypto"
	"github.com/layer-3/nitrolite/pkg/sign"
)

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

	// Create a signature using our signer
	pkHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
	signer, err := sign.NewEthereumRawSigner(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 EthereumMsgAddressRecoverer

type EthereumMsgAddressRecoverer struct{}

EthereumAddressRecoverer implements the AddressRecoverer interface for Ethereum.

func (*EthereumMsgAddressRecoverer) RecoverAddress

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

RecoverAddress implements the AddressRecoverer interface.

type EthereumMsgSigner

type EthereumMsgSigner struct {
	Signer
}

EthereumRawSigner is the implementation of the Signer interface for Ethereum Msg signing.

func (*EthereumMsgSigner) Sign

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

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

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 EthereumRawAddressRecoverer

type EthereumRawAddressRecoverer struct{}

EthereumRawAddressRecoverer implements the AddressRecoverer interface for Ethereum.

Example

ExampleEthereumAddressRecoverer demonstrates using the generic AddressRecoverer interface.

package main

import (
	"fmt"
	"log"

	ethcrypto "github.com/ethereum/go-ethereum/crypto"
	"github.com/layer-3/nitrolite/pkg/sign"
)

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

	// Create a signer
	pkHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
	signer, err := sign.NewEthereumRawSigner(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.EthereumRawAddressRecoverer{}
	// 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 (*EthereumRawAddressRecoverer) RecoverAddress

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

RecoverAddress implements the AddressRecoverer interface.

type EthereumRawSigner

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

EthereumRawSigner is the Ethereum implementation of the Signer interface.

func (*EthereumRawSigner) PublicKey

func (s *EthereumRawSigner) PublicKey() PublicKey

func (*EthereumRawSigner) Sign

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

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

type MockAddress

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

func NewMockAddress(id string) *MockAddress

NewMockAddress creates a new MockAddress with the given ID.

func (*MockAddress) Equals

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

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

func (*MockAddress) String

func (m *MockAddress) String() string

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

type MockPublicKey

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

func NewMockPublicKey(id string) *MockPublicKey

NewMockPublicKey creates a new MockPublicKey with the given ID.

func (*MockPublicKey) Address

func (m *MockPublicKey) Address() Address

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

func (*MockPublicKey) Bytes

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

Bytes returns the ID as a byte slice.

type MockSigner

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

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

func (m *MockSigner) PublicKey() PublicKey

PublicKey returns the mock public key associated with this signer.

func (*MockSigner) Sign

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 SigValidator

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

func NewSigValidator

func NewSigValidator(sigType Type) (*SigValidator, error)

func (*SigValidator) Recover

func (s *SigValidator) Recover(data, sig []byte) (string, error)

func (*SigValidator) Verify

func (s *SigValidator) Verify(wallet string, data, sig []byte) error

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/layer-3/nitrolite/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 NewEthereumMsgSigner

func NewEthereumMsgSigner(privateKeyHex string) (Signer, error)

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

func NewEthereumMsgSignerFromRaw

func NewEthereumMsgSignerFromRaw(signer Signer) (Signer, error)

NewEthereumRawSignerFronRaw creates a new Ethereum signer from an existing Signer instance.

func NewEthereumRawSigner

func NewEthereumRawSigner(privateKeyHex string) (Signer, error)

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

Example

ExampleNewEthereumRawSigner demonstrates creating an Ethereum signer and signing a message.

package main

import (
	"fmt"
	"log"

	ethcrypto "github.com/ethereum/go-ethereum/crypto"
	"github.com/layer-3/nitrolite/pkg/sign"
)

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

	// Create a new Ethereum signer. It returns the generic sign.Signer interface.
	signer, err := sign.NewEthereumRawSigner(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 (
	TypeRawEthereum Type = iota
	TypeEthereumMsg
	TypeUnknown = 255
)

func (Type) String

func (t Type) String() string

String returns the string representation of the algorithm.

Directories

Path Synopsis
kms
Package kms provides shared utilities for KMS-based Ethereum signers.
Package kms provides shared utilities for KMS-based Ethereum signers.
gcp
Package gcpkms implements sign.Signer using Google Cloud KMS.
Package gcpkms implements sign.Signer using Google Cloud KMS.

Jump to

Keyboard shortcuts

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