MPC Link to heading

  • MPC(Multi-Party Computation)多方计算

  • 利用 MPC 技术可将私钥分片, 每个分片由不同的参与方保管, 通过 m/n 个分片聚合出私钥(或签名)。

  • SSS ( Shamir’s Secret Sharing ):聚合后签名

  • TSS( Threshold Signature Scheme ):聚合签名 ,大多数项目采用的方案

  • 部分分片泄露,私钥仍然安全,降低了单点故障风险

MPC 钱包 Link to heading

  • OKX Wallet: 2/3 MPC TSS 方案

  • OKX Cloud 分片

  • 用户设备分片

  • Google Cloud、iCloud 等云备份

  • Para MPC 方案:利用 passkey 为 Dapp 应用提供嵌入式钱包体验, 2-2 MPC方案

  • 用户设备分片、Passkey 云同步(Google Cloud、iCloud 等可跨设备)

  • Para Cloud Share (用户可额外备份)

  • 其他的钱包服务商:Dynamic、Turnkey 和 Privy (Stripe 收购)

多个参与方使用各自的私钥分片,通过 MPC 协议协作完成签名,无需重构完整私钥。

example Link to heading

import {
    http,
    parseEther,
    parseGwei
} from 'viem'
import {
    foundry
} from 'viem/chains'
import {
    createPublicClient,
    createWalletClient
} from 'viem'
import {
    privateKeyToAccount
} from 'viem/accounts'
import {
    split,
    combine
} from 'shamirs-secret-sharing'
import dotenv from 'dotenv'

dotenv.config()

// 生成私钥分片
function generatePrivateKeyShares(privateKey, totalShares, threshold) {
    // 将私钥转换为 Buffer
    const privateKeyBuffer = Buffer.from(privateKey.slice(2), 'hex')

    // 生成分片
    const shares = split(privateKeyBuffer, {
        shares: totalShares,
        threshold
    })
    return shares
}

// 从分片恢复私钥
function recoverPrivateKey(shares) {
    // 恢复私钥
    const recoveredBuffer = combine(shares)
    return '0x' + recoveredBuffer.toString('hex')
}

// 添加验证函数
function verifyShares(shares, originalPrivateKey, threshold) {
    console.log('\n验证所有分片:')
    const allRecoveredKey = recoverPrivateKey(shares)
    console.log('原始私钥:', originalPrivateKey)
    console.log('使用所有分片恢复的私钥:', allRecoveredKey)
    console.log('是否一致:', originalPrivateKey === allRecoveredKey)

    console.log('\n验证部分分片:')
    const partialShares = shares.slice(0, threshold)
    const partialRecoveredKey = recoverPrivateKey(partialShares)
    console.log('使用部分分片恢复的私钥:', partialRecoveredKey)
    console.log('是否一致:', originalPrivateKey === partialRecoveredKey)

    return originalPrivateKey === partialRecoveredKey
}

// 模拟 MPC 签名过程
async function mpcSignTransaction(shares, threshold, transaction) {
    // 1. 恢复私钥
    const recoveredPrivateKey = recoverPrivateKey(shares.slice(0, threshold))
    console.log('恢复的私钥:', recoveredPrivateKey)


    const account = privateKeyToAccount(recoveredPrivateKey)
    const walletClient = createWalletClient({
        account: account,
        chain: foundry,
        transport: http(process.env.RPC_URL)
    })

    // 2. 签名交易
    const signedTx = await walletClient.signTransaction(transaction)

    return signedTx
}

async function sendTransactionWithMPC() {
    try {
        // 1. 从环境变量获取私钥
        const privateKey = process.env.PRIVATE_KEY
        if (!privateKey) {
            throw new Error('请在 .env 文件中设置 PRIVATE_KEY')
        }
        console.log('原始私钥:', privateKey)

        // 2. 创建公共客户端
        const publicClient = createPublicClient({
            chain: foundry,
            transport: http(process.env.RPC_URL)
        })

        // 3. 从私钥创建账户
        const account = privateKeyToAccount(privateKey)
        const userAddress = account.address
        console.log('账户地址:', userAddress)

        // 4. 生成私钥分片 (5个分片,需要3个分片才能恢复)
        const totalShares = 5
        const threshold = 3
        const shares = generatePrivateKeyShares(privateKey, totalShares, threshold)
        console.log(`生成了 ${totalShares} 个私钥分片,需要 ${threshold} 个分片才能恢复私钥`)

        // 验证分片恢复
        verifyShares(shares, privateKey, threshold)

        // 6. 检查网络状态
        const blockNumber = await publicClient.getBlockNumber()
        console.log('当前区块号:', blockNumber)

        // 7. 获取当前 gas 价格
        const gasPrice = await publicClient.getGasPrice()
        console.log('当前 gas 价格:', parseGwei(gasPrice.toString()))

        // 8. 查询余额
        const balance = await publicClient.getBalance({
            address: userAddress
        })
        console.log('账户余额:', parseEther(balance.toString()))

        // 9. 查询 nonce
        const nonce = await publicClient.getTransactionCount({
            address: userAddress
        })
        console.log('当前 Nonce:', nonce)

        // 10. 构建交易参数
        const txParams = {
            account: account,
            to: '0x01BF49D75f2b73A2FDEFa7664AEF22C86c5Be3df',
            value: parseEther('0.001'),
            chainId: foundry.id,
            type: 'eip1559',
            chain: foundry,
            maxFeePerGas: gasPrice * 2n,
            maxPriorityFeePerGas: parseGwei('1.5'),
            gas: 21000n,
            nonce: nonce,
        }

        // 12. 使用 MPC 签名交易
        console.log('开始 MPC 签名过程...')
        const signedTx = await mpcSignTransaction(shares, threshold, txParams)
        console.log('MPC 签名完成')

        // 13. 发送交易
        const txHash = await publicClient.sendRawTransaction({
            serializedTransaction: signedTx
        })
        console.log('Transaction Hash:', txHash)

        // 14. 等待交易确认
        const receipt = await publicClient.waitForTransactionReceipt({
            hash: txHash
        })
        console.log('交易状态:', receipt.status === 'success' ? '成功' : '失败')
        console.log('区块号:', receipt.blockNumber)
        console.log('Gas 使用量:', receipt.gasUsed.toString())

        return txHash

    } catch (error) {
        console.error('错误:', error)
        if (error instanceof Error) {
            console.error('错误信息:', error.message)
        }
        if (error && typeof error === 'object' && 'details' in error) {
            console.error('错误详情:', error.details)
        }
        throw error
    }
}

// 执行示例
sendTransactionWithMPC()