Skip to main content

一次性无私钥地址发送交易

通过直接随机生成r、s、v来构建签名,然后通过签名恢复出来address。这种情况下,可以通过这个签名发送交易,但是不知道私钥是什么。也就是这个地址用完就废弃了。所以叫一次性无私钥地址交易

背景问题: The DAO’s Edge Cases Multisig (Post Hard Fork) 解决思路: How to send Ether to 11,440 people

一次性无私钥地址交易构建

import { BigNumber, ethers, utils, UnsignedTransaction } from "ethers";

const secp256k1n = BigNumber.from(
"115792089237316195423570985008687907852837564279074904382605163141518161494337" // 2^256
);

const without0x = (value: string) => Array.from(value).slice(2).join("");

function generateTx() {
const rawTx: UnsignedTransaction = {
chainId: 1,
nonce: 0,
value: BigNumber.from(10).pow(18), // 1e18
gasLimit: 5,
gasPrice: 10,
};

// 0 < r < secp256k1n
// 0 < s < secp256k1n ÷ 2 + 1
// and according to EIP-155 https://eips.ethereum.org/EIPS/eip-155 :
// v ∈ {27, 28}
const r = BigNumber.from(utils.hexlify(utils.randomBytes(64))).mod(
secp256k1n
);
const s = BigNumber.from(utils.hexlify(utils.randomBytes(64))).mod(
secp256k1n.div(2).add(1)
);
const v = BigNumber.from(Math.random() > 0.5 ? 27 : 28);

const rHex = r.toHexString();
const rHexPadded = ethers.utils.hexZeroPad(rHex, 32); // Ensure 32 bytes long
const sHex = s.toHexString();
const sHexPadded = ethers.utils.hexZeroPad(sHex, 32); // Ensure 32 bytes long

const vHex = v.toHexString();
// 生成签名
const signature = `0x${without0x(rHexPadded)}${without0x(
sHexPadded
)}${without0x(vHex)}`;
const rawUnsignedTx = ethers.utils.serializeTransaction(rawTx);
const unsignedTxHash = ethers.utils.keccak256(rawUnsignedTx);

// 通过签名恢复出address
const address = ethers.utils.recoverAddress(unsignedTxHash, signature);
// 生成好的签名交易
const rawTransaction = ethers.utils.serializeTransaction(rawTx, signature);
// 把交易发出去...
}

参考代码: single-use-address-generator

参考文档