Skip to content

Repository files navigation

BIP-322 Starknet Account

A Starknet account contract that enables Bitcoin wallets to control Starknet accounts via BIP-322 message signing

Build Status License: MIT


Overview

This project implements a Starknet account contract that verifies BIP-322 Bitcoin message signatures, allowing Bitcoin wallets to directly control Starknet accounts through Starknet's account abstraction.

What is BIP-322?

BIP-322 (Bitcoin Improvement Proposal 322) defines a generic message signing format for Bitcoin. Unlike the legacy Bitcoin message signing (which only worked for P2PKH addresses), BIP-322 supports all Bitcoin address types including:

  • P2WPKH (Native SegWit) - bc1q... addresses ✅ (supported by this contract)
  • P2SH-P2WPKH (Wrapped SegWit)
  • P2TR (Taproot)

BIP-322 works by creating a virtual "to-sign" transaction that commits to the message, then producing a witness that proves ownership of the address.

How It Works with Starknet Account Abstraction

Starknet's native account abstraction allows custom signature verification logic in smart contracts. This project leverages that capability to:

  1. Store a Bitcoin public key hash (hash160 of the compressed public key) as the account owner
  2. Verify BIP-322 signatures on-chain using the alexandria_btc library
  3. Enable Bitcoin wallets to sign Starknet transactions without any intermediary
┌─────────────────┐         ┌───────────────────┐         ┌──────────────────┐
│  Bitcoin Wallet │ ──────► │  BIP-322 Message  │ ──────► │ Starknet Account │
│  (e.g. Xverse)  │  signs  │  Signature        │ verifies│ Contract         │
└─────────────────┘         └───────────────────┘         └──────────────────┘
                                                                    │
                                                                    ▼
                                                          ┌──────────────────┐
                                                          │ Execute Starknet │
                                                          │ Transactions     │
                                                          └──────────────────┘

Execution Modes

The account supports two execution modes:

1. Direct Execution

Standard Starknet account execution where the BIP-322 account signs and broadcasts transactions directly:

┌────────────────┐     ┌─────────────────┐     ┌──────────────────┐
│  BTC Wallet    │────►│  Sign tx hash   │────►│  BtcAccount      │
│  signs message │     │  (hex string)   │     │  __validate__()  │
└────────────────┘     └─────────────────┘     └────────┬─────────┘
                                                        │
                                                        ▼
                                               ┌──────────────────┐
                                               │  __execute__()   │
                                               │  Execute calls   │
                                               └──────────────────┘

The message signed is the transaction hash as a 64-character hex string (lowercase, padded with leading zeros).

2. Outside Execution (SNIP-9 / SRC-9)

Enables gasless/sponsored transactions where a third party can execute transactions on behalf of the BIP-322 account:

┌────────────────┐     ┌─────────────────────┐     ┌───────────────────┐
│  BTC Wallet    │────►│  Sign OutsideExec   │────►│  Sender/Paymaster │
│  signs message │     │  JSON structure     │     │  broadcasts tx    │
└────────────────┘     └─────────────────────┘     └─────────┬─────────┘
                                                             │
                                                             ▼
                                               ┌───────────────────────────┐
                                               │  BtcAccount               │
                                               │  execute_from_outside_v2()│
                                               └───────────────────────────┘

This implements the SNIP-9 standard for outside execution.

Message Signing Format

The Challenge: No EIP-712 Equivalent for Bitcoin

Unlike Ethereum which has EIP-712 for typed structured data signing, Bitcoin has no standardized typed data format. BIP-322 only supports signing arbitrary byte strings.

This creates several challenges:

  1. Messages are signed as plain strings - Users see raw JSON in their Bitcoin wallet
  2. Exact format matching is critical - The on-chain contract must reconstruct the exact same string
  3. Case sensitivity matters - "Caller""caller"
  4. Whitespace and ordering matter - Any difference in JSON structure will cause verification failure

Outside Execution Message Format

For outside execution, the signed message is a JSON structure:

{
  "userAddress": "0x0203aeb387aa85d858b170f62c8b27b43f877f6d765de16d4967c3d3677d49bc",
  "primaryType": "OutsideExecution",
  "domain": {
    "name": "Account.execute_from_outside",
    "version": "2",
    "chainId": "0x534e5f5345504f4c4941",
    "revision": "1"
  },
  "message": {
    "Caller": "0x...",
    "Nonce": "0x...",
    "Execute After": "0x...",
    "Execute Before": "0x...",
    "Calls": [...]
  }
}

⚠️ Important: The JSON keys use specific casing (e.g., "Execute After" with space and capitals). Both the signing client and on-chain contract must produce byte-identical strings.

💡 Tip: Examples and utilities for generating correctly formatted messages can be found in the bip322-account-examples/ directory. See bip322-utils.ts for message formatting helpers.

Contract Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                        BtcAccountPreset                              │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │                    BtcAccountComponent                           ││
│  │  ┌───────────────┐  ┌───────────────┐  ┌─────────────────────┐ ││
│  │  │   Storage     │  │   SRC6 Impl   │  │   SRC9_V2 Impl      │ ││
│  │  │ ─────────────-│  │ ─────────────-│  │ ───────────────────-│ ││
│  │  │ pubkey_hash   │  │ __execute__   │  │ execute_from_       │ ││
│  │  │ nonces        │  │ __validate__  │  │   outside_v2        │ ││
│  │  └───────────────┘  │ is_valid_sig  │  └─────────────────────┘ ││
│  │                     └───────────────┘                           ││
│  │  ┌─────────────────────────────────────────────────────────────┐││
│  │  │                    Internal Functions                        │││
│  │  │ • _is_valid_signature() - Verify BIP-322 signatures         │││
│  │  │ • validate_signature_with_message() - Message verification  │││
│  │  │ • get_btc_address() - Convert pubkey_hash to bech32 address │││
│  │  └─────────────────────────────────────────────────────────────┘││
│  └─────────────────────────────────────────────────────────────────┘│
│  ┌────────────────────┐  ┌────────────────────────────────────────┐ │
│  │   SRC5Component    │  │        UpgradeableComponent            │ │
│  │   (introspection)  │  │        (contract upgrades)             │ │
│  └────────────────────┘  └────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

Key Components

Component Description
BtcAccountComponent Core account logic with BIP-322 signature verification
BtcAccountPreset Ready-to-deploy account contract with upgradability
SRC6 Standard Starknet account interface (__execute__, __validate__)
SRC9_V2 Outside execution interface for gasless transactions

Dependencies

This project heavily relies on the alexandria_btc library from Alexandria for Bitcoin-related cryptographic operations:

  • bip322_msg_hash_p2wpkh - Computes the BIP-322 message hash for P2WPKH addresses
  • verify_ecdsa_signature_auto_recovery - Verifies secp256k1 ECDSA signatures
  • hash160_from_byte_array - Computes RIPEMD160(SHA256(data))
  • decode_address / pubkey_hash_to_address - Bech32 address encoding/decoding
[dependencies]
alexandria_btc = "0.9"
alexandria_encoding = "0.9"
alexandria_bytes = "0.9"
openzeppelin_account = "2.0.0"

Installation & Building

Prerequisites

Build

# Clone the repository
git clone https://github.com/keep-starknet-strange/bip-322-account.git
cd bip-322-account

# Build the contracts
scarb build

Run Tests

snforge test

Build for Release

scarb build --release

The compiled contracts will be available in target/release/:

  • starknet_bip322_account_BtcAccountPreset.contract_class.json
  • starknet_bip322_account_BtcAccountPreset.compiled_contract_class.json

Declare Contract

To declare the contract on Starknet (e.g., Sepolia testnet):

sncast --account <YOUR_ACCOUNT> declare \
  --contract-name BtcAccountPreset \
  --url <RPC_URL>

This will output a class hash that you'll use for deployment.

Deploy Account

To deploy a new BIP-322 account, use the class hash from the declaration step:

sncast --account <YOUR_ACCOUNT> deploy \
  --class-hash <CLASS_HASH> \
  --arguments '"<BITCOIN_ADDRESS>"' \
  --url <RPC_URL>

Example:

# Deploy with a P2WPKH Bitcoin address
sncast --account my-account deploy \
  --class-hash 0x13ec6645b98e4c3b64e9c74fe4331b43907ea1fd8ae94547d7174976f91859d \
  --arguments '"bc1q4gsm3wweqg66aynahflxtqx9540gspcmthehxj"' \
  --url https://starknet-sepolia.public.blastapi.io/rpc/v0_8

Note: The Bitcoin address must be a valid P2WPKH (native SegWit) address starting with bc1q.... The address is passed as a ByteArray, hence the nested quotes '"..."'.

Usage Examples

See the bip322-account-examples/ directory for TypeScript examples demonstrating:

Example Description
sign-and-send.ts Direct transaction signing and execution
outside-execution-bip322.ts Gasless transactions via outside execution
paymaster-bip322.ts Paymaster-sponsored transactions

Quick Start

cd bip322-account-examples
npm install
# Configure .env with your Bitcoin private key and Starknet RPC
npx ts-node src/sign-and-send.ts

References

⚠️ Disclaimer

THIS SOFTWARE IS EXPERIMENTAL AND PROVIDED "AS IS".

  • Not audited: The contracts and code in this repository have NOT been audited by a professional security firm.
  • Use at your own risk: This software is intended for educational and experimental purposes only. Do not use with significant funds.
  • No warranty: The authors make no guarantees about the security, correctness, or reliability of this software.
  • Testnet recommended: It is strongly recommended to test thoroughly on Starknet testnet (Sepolia) before any mainnet usage.

If you plan to use this in a production environment, please conduct a thorough security audit first.

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages