Skip to content

Blockchain Integration

SirrChat's blockchain integration enables passwordless authentication using EVM wallet signatures. This innovative approach eliminates traditional password vulnerabilities while providing cryptographically secure access control.

Overview

The blockchain authentication module (auth.pass_blockchain) allows users to authenticate using their Ethereum (or EVM-compatible) wallet signatures instead of traditional passwords.

How It Works

  1. User Registration: User's wallet address is registered with the email account
  2. Authentication Request: Client signs a challenge message with their private key
  3. Signature Verification: Server recovers the public key from the signature
  4. Access Grant: If the recovered address matches the registered address, access is granted

Configuration

Basic Setup

Add blockchain authentication to your sirrchatd.conf:

conf
# Blockchain configuration
blockchain sirrchatd {
    rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
    chain_id 1  # Ethereum Mainnet
}

# Authentication module
auth.pass_blockchain blockchain_auth {
    blockchain &sirrchatd
    storage &local_mailboxes
}

# Use in IMAP endpoint
imap tls://0.0.0.0:993 {
    auth &blockchain_auth
    storage &local_mailboxes
}

Supported Chains

SirrChat supports any EVM-compatible blockchain:

ChainChain IDNetwork
Ethereum Mainnet1Production
Ethereum Goerli5Testnet
Ethereum Sepolia11155111Testnet
BSC Mainnet56Production
BSC Testnet97Testnet
Polygon Mainnet137Production
Polygon Mumbai80001Testnet
Arbitrum One42161Production
Optimism10Production

Authentication Flow

1. Challenge Generation

When a user attempts to authenticate, the server generates a challenge message:

Challenge: <random_nonce>
Timestamp: <unix_timestamp>
Service: sirrchat

2. Client-Side Signing

The client signs the challenge using their Ethereum wallet:

javascript
// Example using ethers.js
const message = `Challenge: ${nonce}\nTimestamp: ${timestamp}\nService: sirrchat`;
const signature = await wallet.signMessage(message);

3. Server-Side Verification

The server verifies the signature and recovers the address:

go
// Internal verification process
func (bc *Ethereum) CheckSign(ctx context.Context, pk, sign, message string) (bool, error) {
    hash := crypto.Keccak256Hash([]byte(message))
    signature := hexutil.MustDecode(sign)

    // Recover public key from signature
    pubKey, err := crypto.SigToPub(hash.Bytes(), signature)
    if err != nil {
        return false, err
    }

    // Get address from public key
    recoveredAddr := crypto.PubkeyToAddress(*pubKey)

    // Compare with registered address
    return recoveredAddr.Hex() == pk, nil
}

User Management

Register Blockchain User

bash
# Register a wallet address with an email account
sirrchatd creds create-blockchain \
    --email user@example.com \
    --address 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb

# List blockchain users
sirrchatd creds list-blockchain

Update Wallet Address

bash
# Update wallet address for an existing account
sirrchatd creds update-blockchain \
    --email user@example.com \
    --address 0xNewAddress

Remove Blockchain Authentication

bash
# Remove blockchain auth (keep email account)
sirrchatd creds remove-blockchain --email user@example.com

Client Implementation

Email Client Configuration

Configure your email client to use blockchain authentication:

IMAP Settings:

  • Server: your-domain.com
  • Port: 993
  • Security: SSL/TLS
  • Username: user@example.com
  • Password: <signature> (the wallet signature)

Custom Client Example

Here's a simple example of implementing blockchain auth in a custom client:

javascript
const ethers = require('ethers');

class BlockchainEmailAuth {
    constructor(walletAddress, privateKey) {
        this.wallet = new ethers.Wallet(privateKey);
        this.address = walletAddress;
    }

    async generateAuthCredentials(challenge, timestamp) {
        const message = `Challenge: ${challenge}\nTimestamp: ${timestamp}\nService: sirrchat`;
        const signature = await this.wallet.signMessage(message);

        return {
            username: `user@example.com`,
            password: signature,
            address: this.address
        };
    }

    async connectIMAP(host, port) {
        // Get challenge from server
        const { challenge, timestamp } = await this.getChallengeFromServer();

        // Generate credentials
        const creds = await this.generateAuthCredentials(challenge, timestamp);

        // Connect to IMAP server
        // ... use creds to authenticate
    }
}

Security Considerations

Best Practices

  1. Never Share Private Keys: Private keys should never be transmitted or stored on the server
  2. Use Hardware Wallets: For production use, consider hardware wallet integration
  3. Implement Nonce Expiry: Challenge nonces should expire after a short period
  4. Rate Limiting: Implement rate limiting on authentication attempts
  5. Audit Logging: Log all authentication attempts for security monitoring

Replay Attack Prevention

The server includes anti-replay protections:

conf
auth.pass_blockchain blockchain_auth {
    blockchain &sirrchatd
    storage &local_mailboxes

    # Challenge configuration
    challenge_expiry 300s  # 5 minutes
    nonce_cache_size 10000
}

Advantages Over Traditional Authentication

Security Benefits

  • No Password Storage: Eliminates password database breaches
  • Cryptographic Verification: Based on proven elliptic curve cryptography
  • No Password Reuse: Each signature is unique
  • Phishing Resistant: Cannot be tricked into revealing credentials

User Experience

  • No Password Management: Users don't need to remember passwords
  • Multi-Device: Same wallet can be used across all devices
  • Recovery Options: Use wallet recovery mechanisms instead of password resets

Integration with Web3 Applications

DApp Integration

Integrate email functionality into your DApp:

javascript
// Example: Send email from DApp
async function sendEmailFromDApp(web3Provider) {
    const signer = web3Provider.getSigner();
    const address = await signer.getAddress();

    // Get challenge
    const challenge = await fetchChallenge();

    // Sign challenge
    const signature = await signer.signMessage(challenge.message);

    // Authenticate and send email
    await sendEmail({
        from: `${address}@yourdomain.com`,
        signature: signature,
        to: 'recipient@example.com',
        subject: 'Hello from DApp',
        body: 'This email was sent using blockchain authentication!'
    });
}

Troubleshooting

Common Issues

Signature Verification Fails

bash
# Check if address is registered
sirrchatd creds list-blockchain | grep user@example.com

# Verify challenge format
# Ensure client and server use the same message format

RPC Connection Issues

bash
# Test RPC endpoint
curl -X POST https://mainnet.infura.io/v3/YOUR_PROJECT_ID \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'

Advanced Configuration

Multiple Chain Support

conf
# Support multiple chains
blockchain eth_mainnet {
    rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
    chain_id 1
}

blockchain bsc_mainnet {
    rpc_endpoint https://bsc-dataseed1.binance.org
    chain_id 56
}

auth.pass_blockchain multi_chain_auth {
    blockchain &eth_mainnet &bsc_mainnet
    storage &local_mailboxes
}

Custom Verification Logic

Extend the blockchain module for custom verification:

go
// Custom verification implementation
type CustomBlockchainAuth struct {
    baseAuth *blockchain.Ethereum
}

func (c *CustomBlockchainAuth) VerifyWithNFT(ctx context.Context, address, signature string) (bool, error) {
    // Verify signature
    valid, err := c.baseAuth.CheckSign(ctx, address, signature, message)
    if err != nil || !valid {
        return false, err
    }

    // Additional NFT ownership check
    hasNFT, err := c.checkNFTOwnership(ctx, address)
    return hasNFT, err
}

API Reference

Core Interface

go
type BlockChain interface {
    // Send raw transaction to blockchain
    SendRawTx(ctx context.Context, rawTx string) error

    // Get blockchain type
    ChainType(ctx context.Context) string

    // Verify signature and check if it matches public key
    CheckSign(ctx context.Context, pk, sign, message string) (bool, error)
}

Resources


Blockchain authentication eliminates passwords while enhancing security through cryptographic verification.

Released under the GPL 3.0 License.