Crate chain_signatures

Crate chain_signatures 

Source
Expand description

§Signet Chain Signatures Program

Solana program for cross-chain signature requests with verified response callbacks.

§Overview

This program enables users to request ECDSA signatures from the Signet MPC network, supporting both simple signing and bidirectional cross-chain transactions.

§Instructions Reference

§Developer Instructions

These are the primary instructions for building applications:

InstructionDescription
signRequest signature on a 32-byte payload
sign_bidirectionalCross-chain tx with execution result callback
get_signature_depositQuery the current deposit amount (view function)

§Sign Bidirectional Flow

The bidirectional flow enables cross-chain transaction execution with verified response callbacks:

User                    Solana (Source)         MPC Network        Destination Chain
  │                        │                         │                    │
  │ sign_bidirectional()   │                         │                    │
  ├───────────────────────►│                         │                    │
  │                        │  SignBidirectionalEvent │                    │
  │                        ├────────────────────────►│                    │
  │                        │◄──── respond() ─────────┤                    │
  │                        │                         │                    │
  │ Poll SignatureRespondedEvent                     │                    │
  │◄───────────────────────┤                         │                    │
  │                        │                         │                    │
  │ Broadcast signed tx ───┼─────────────────────────┼───────────────────►│
  │                        │                         │◄── Light client ───┤
  │                        │◄─ respond_bidirectional()                    │
  │                        │                         │                    │
  │ Poll RespondBidirectionalEvent                   │                    │
  │◄───────────────────────┤                         │                    │

§Phase 1: Sign Request

  1. User calls sign_bidirectional with serialized unsigned transaction
  2. Program emits SignBidirectionalEvent
  3. MPC parses event and generates unique request ID

§Phase 2: Signature Delivery

  1. MPC signs the transaction hash
  2. Stores transaction in backlog for observation
  3. Calls respond, emitting SignatureRespondedEvent
  4. User polls for SignatureRespondedEvent to get signature

§Phase 3: User Broadcast

  1. User assembles signed transaction (serialized data + signature)
  2. User broadcasts to destination chain
  3. The MPC does NOT broadcast - this is the user’s responsibility

§Phase 4: Light Client Observation

  1. MPC light client monitors destination chain blocks
  2. Detects transaction confirmation by hash
  3. Extracts execution status (success/failure)

§Phase 5: Output Extraction

  1. For contract calls: MPC extracts return value
  2. For simple transfers: empty success indicator
  3. Output deserialized using output_deserialization_schema

§Phase 6: Respond Bidirectional

  1. MPC serializes output using respond_serialization_schema
  2. Signs keccak256(request_id || serialized_output)
  3. Calls respond_bidirectional
  4. Program emits RespondBidirectionalEvent for user to poll

§Request ID Generation

Each request has a unique ID for tracking:

// For sign_bidirectional (packed encoding):
request_id = keccak256(
    sender || serialized_tx || caip2_id || key_version ||
    path || algo || dest || params
)

§Serialization Schemas

Cross-chain data encoding uses two schemas:

SchemaDirectionPurpose
output_deserialization_schemaDestination → MPCParse execution result from destination chain
respond_serialization_schemaMPC → SourceSerialize response for source chain consumption

See destination chain guides (e.g., EVM) for format details and examples.

§Error Handling

Failed destination chain transactions are indicated with magic prefix:

const MAGIC_ERROR_PREFIX: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];

// Check if response indicates failure:
fn is_error(output: &[u8]) -> bool {
    output.starts_with(&[0xde, 0xad, 0xbe, 0xef])
}

§Address Derivation

Each user gets a unique destination chain address derived from:

epsilon = derive_epsilon(sender_pubkey, derivation_path)
user_pubkey = derive_key(mpc_root_pubkey, epsilon)
// Address format is chain-specific (see destination chain guides)

§Response Signature Verification

The respond_bidirectional response is signed using a special derivation path:

const RESPONSE_DERIVATION_PATH: &str = "solana response key";

// Response epsilon derivation:
epsilon = derive_epsilon(key_version, sender_pubkey, "solana response key")
response_pubkey = derive_key(mpc_root_pubkey, epsilon)

The signature is computed over:

message_hash = keccak256(request_id || serialized_output)

To verify the response signature, clients must:

  1. Recover the public key from the signature using secp256k1_recover
  2. Derive the expected response public key using the "solana response key" path
  3. Compare the recovered public key with the expected response public key

§Security Considerations

§Security Properties

  1. Request ID Uniqueness: Each request has a unique ID computed from keccak256(sender || tx || chain_id || ...) preventing replay attacks

  2. Response Authenticity: Responses are signed over keccak256(request_id || serialized_output) using MPC threshold signatures

  3. Output Verification: The output_deserialization_schema and respond_serialization_schema ensure consistent data encoding across chains

  4. Key Isolation: Each user has isolated keys through unique derivation paths (epsilon = derive_epsilon(predecessor, path))

  5. Light Client Security: The MPC light client validates destination chain consensus without trusting an RPC provider

§Destination Chain Guides

For detailed integration guides with real code examples, see:

  • EVM - Solana → EVM (Ethereum, Arbitrum, Optimism, Base, Polygon)

§License

MIT

Modules§

accounts
An Anchor generated module, providing a set of structs mirroring the structs deriving Accounts, where each field is a Pubkey. This is useful for specifying accounts for a client.
chain_signatures
evm
Solana → EVM Destination Chain Integration Guide
instruction
An Anchor generated module containing the program’s set of instructions, where each method handler in the #[program] mod is associated with a struct defining the input arguments to the method. These should be used directly, when one wants to serialize Anchor instruction data, for example, when speciying instructions on a client.
program
Module representing the program.

Structs§

AdminOnly
AdminOnlyBumps
AffinePoint
A point on the secp256k1 elliptic curve in affine coordinates.
DepositUpdatedEvent
Emitted when the admin updates the signature deposit via chain_signatures::update_deposit.
ErrorResponse
Error information for failed signature requests.
FundsWithdrawnEvent
Emitted when the admin withdraws funds via chain_signatures::withdraw_funds.
GetSignatureDeposit
GetSignatureDepositBumps
Initialize
InitializeBumps
ProgramState
Program configuration state stored in a PDA.
ReadRespond
ReadRespondBumps
Respond
RespondBidirectionalEvent
Emitted when the MPC network returns execution results for a bidirectional request via chain_signatures::respond_bidirectional.
RespondBumps
RespondError
RespondErrorBumps
Sign
SignBidirectional
SignBidirectionalBumps
SignBidirectionalEvent
Emitted when a bidirectional cross-chain request is made via chain_signatures::sign_bidirectional.
SignBumps
Signature
ECDSA signature in affine point representation.
SignatureErrorEvent
Emitted when signature generation fails via chain_signatures::respond_error.
SignatureRequestedEvent
Emitted when a signature is requested via the chain_signatures::sign instruction.
SignatureRespondedEvent
Emitted when the MPC network returns a signature via chain_signatures::respond.
WithdrawFunds
WithdrawFundsBumps

Enums§

ChainSignaturesError

Constants§

ID_CONST
Const version of ID

Statics§

ID
The static program ID

Functions§

check_id
Confirms that a given pubkey is equivalent to the program ID
entry
The Anchor codegen exposes a programming model where a user defines a set of methods inside of a #[program] module in a way similar to writing RPC request handlers. The macro then generates a bunch of code wrapping these user defined methods into something that can be executed on Solana.
entrypoint
Safety
id
Returns the program ID
id_const
Const version of ID