Skip to main content
The account model in BRC2.0 differs fundamentally from Ethereum. Understanding this before you write any authorization logic will save you from hard-to-debug security issues.

No private keys for EVM addresses

EVM addresses in BRC2.0 do not have associated private keys. An EVM address is deterministically derived from a Bitcoin wallet’s output script (pkscript) using:
evm_address = keccak256(bitcoin_pkscript_bytes)[12:]
This address exists solely as an execution identity inside the EVM. It cannot sign messages and cannot produce Ethereum-style ECDSA signatures. Any authentication scheme that assumes the existence of an ECDSA key for an EVM address will not work.
Different Bitcoin addresses or scripts produce different EVM addresses, even if they are controlled by the same wallet software.

Bitcoin wallet as identity

A user’s Bitcoin wallet is their identity. Ownership and intent are proven by signing messages using Bitcoin keys and submitting those signatures alongside contract calls. The EVM address derived from the wallet script serves as the canonical on-chain identifier for that user.

BIP-322 instead of ecrecover

Ethereum’s ecrecover precompile cannot be used for authentication. Instead, authentication is performed using BIP-322 message signatures, verified inside smart contracts via a dedicated precompile.

Verification flow

1

User signs a message

The user signs a message using their Bitcoin wallet (BIP-322). This can be done with any compatible Bitcoin wallet.
2

Pass signature as calldata

The signature and the signed message are ABI-encoded and passed as calldata when inscribing the contract call.
3

Contract calls the BIP-322 precompile

Inside the contract, call the BIP-322 verification precompile with the message and signature.
4

Precompile returns the derived EVM address

If verification succeeds, the precompile returns the EVM address derived from the signing Bitcoin script. Use this address as the authenticated user.

BIP-322 precompile interface

The precompile is deployed at address 0xFE in the BRC2.0 execution environment. It takes the signing wallet’s pkscript, the message, and the BIP-322 signature, and returns a boolean indicating whether the signature is valid.
// Precompile address: 0xFE

interface IBIP322_Verifier {
    function verify(
        bytes calldata pkscript,
        bytes calldata message,
        bytes calldata signature
    ) external returns (bool success);
}
See the Precompiles reference for the full parameter and return documentation.

Example: authenticated action

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

IBIP322_Verifier constant BIP322 = IBIP322_Verifier(address(0xFE));

contract AuthenticatedVault {
    mapping(address => uint256) public balances;

    /// @notice Withdraw assets with explicit BIP-322 authorization.
    /// @param pkscript  The Bitcoin output script of the signing wallet.
    /// @param message   The message that was signed.
    /// @param signature The BIP-322 signature produced by the Bitcoin wallet.
    function withdraw(
        uint256 amount,
        bytes calldata pkscript,
        bytes calldata message,
        bytes calldata signature
    ) external {
        bool valid = BIP322.verify(pkscript, message, signature);
        require(valid, "Invalid BIP-322 signature");

        // Derive the expected EVM address from the pkscript and compare to msg.sender
        address expectedSender = address(uint160(uint256(keccak256(pkscript))));
        require(expectedSender == msg.sender, "Signer must match caller");
        require(balances[msg.sender] >= amount, "Insufficient balance");

        balances[msg.sender] -= amount;
        // ... release assets
    }
}

Interpreting msg.sender

msg.sender represents the derived EVM address of the Bitcoin script that initiated the operation. Think of it as:
“The Bitcoin script that authorized this execution.”
Not as an Ethereum-style externally owned account. Because this address cannot sign, msg.sender alone should not be treated as proof of cryptographic intent. Any action that requires explicit user consent — withdrawals, approvals, upgrades — must additionally verify a BIP-322 signature.
Use msg.sender as a stable identifier for storing balances, permissions, and state. Use BIP-322 verification for any action that requires proof of user intent.

Authorization patterns

Summary

ConceptEthereumBRC2.0
Account typeECDSA keypair (EOA)Derived from Bitcoin pkscript
Address derivationFrom private keykeccak256(pkscript)[12:]
Signature schemeecrecoverBIP-322 precompile at 0xFE
msg.sender meaningEOA that signed the txBitcoin script that initiated op
User identity rootEthereum private keyBitcoin wallet