Skip to content

Blockchain Integration ​

SirrMesh'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 sirrmeshd.conf:

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

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

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

Supported Chains ​

SirrMesh 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
sirrmeshd creds create-blockchain \
    --email [email protected] \
    --address 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb

# List blockchain users
sirrmeshd creds list-blockchain

Update Wallet Address ​

bash
# Update wallet address for an existing account
sirrmeshd creds update-blockchain \
    --email [email protected] \
    --address 0xNewAddress

Remove Blockchain Authentication ​

bash
# Remove blockchain auth (keep email account)
sirrmeshd creds remove-blockchain --email [email protected]

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: [email protected]
  • 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: `[email protected]`,
            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 &bsc
    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: '[email protected]',
        subject: 'Hello from DApp',
        body: 'This email was sent using blockchain authentication!'
    });
}

Troubleshooting ​

Common Issues ​

Signature Verification Fails ​

bash
# Check if address is registered
sirrmeshd creds list-blockchain | grep [email protected]

# 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.