比特幣私鑰、公鑰、地址


隨機生成私鑰

私鑰是 256 位的二進制數,以 64 位 hex 顯示,例如
bef05ca99c4bb9d17f9f164a5bffd48ee2f99f866a3621dd9a4be62412c28148

public static byte[] privateKey() {
	byte[] privateKey = new byte[32];
	random.nextBytes(privateKey);
	return privateKey;
}

從私鑰到公鑰

{K = k * G} secp256k1 標准的橢圓曲線,以私鑰 k 為起點,將曲線上已定義的生成點 G 相乘獲得另一點,也就是公鑰 K = (x, y)。

K = bef05ca99c4bb9d17f9f164a5bffd48ee2f99f866a3621dd9a4be62412c28148 * G
x = c2a0eef93156029532c9b6d33dfd4d09abc3fa0454bc1580230682c9d197f974
y = 0ccafcd456bbac903010082d251b83f8d10013d49e75b1c681c2189c92955f35

公鑰有兩種格式,壓縮與未壓縮。坐標 x 對應兩個 y 值,分別為奇數和偶數,因此可以將 y 壓縮為一個字節:02 表示偶數,03 表示奇數。
未壓縮的公鑰:04 + x + y
已壓縮的公鑰:02 + x 或 03 + x
(bitcoinj 里面地址是由壓縮格式公鑰計算出來的。)

<dependency>
	<groupId>com.madgag.spongycastle</groupId>
	<artifactId>core</artifactId>
	<version>1.58.0.0</version>
</dependency>
private static final ECDomainParameters CURVE;

private static final X9ECParameters CURVE_PARAMS = CustomNamedCurves.getByName("secp256k1");

static {
	FixedPointUtil.precompute(CURVE_PARAMS.getG(), 12);
	CURVE = new ECDomainParameters(CURVE_PARAMS.getCurve(), CURVE_PARAMS.getG(), CURVE_PARAMS.getN(),
			CURVE_PARAMS.getH());
}

private static byte[] fromPrivate(byte[] privKeyBytes) {
	BigInteger privKey = new BigInteger(1, privKeyBytes);
	if (privKey.bitLength() > CURVE.getN().bitLength()) {
		privKey = privKey.mod(CURVE.getN());
	}
	ECPoint multiply = new FixedPointCombMultiplier().multiply(CURVE.getG(), privKey);
	byte[] uncompressed = multiply.getEncoded(false);
	byte[] compressed = multiply.getEncoded(true);
	return compressed;
}

從公鑰 K 到比特幣地址

  1. ripemd160(sha256(K)) 結果長 20 字節
  2. 對 1 添加版本前綴,例如比特幣地址前綴為 0x00
  3. 對 2 做兩次 sha256 並取前 4 字節
  4. 對 2 + 3 做 base58 編碼

base58check: 2,3,4

base58 即 [0-9a-zA-Z] - [0OIl] 數字 0、大寫字母 O I、小寫字母 l

byte[] hashedPubKey = Utils.ripeMD160(Utils.sha256(pubBytes));
base58Check(hashedPubKey);

private static String base58Check(byte[] input) throws Exception {
	byte[] data = new byte[1 + input.length];
	data[0] = 0;
	System.arraycopy(input, 0, data, 1, input.length);

	byte[] checksum = Utils.sha256(data);
	checksum = Utils.sha256(checksum);

	byte[] address = new byte[data.length + 4];
	System.arraycopy(data, 0, address, 0, data.length);
	System.arraycopy(checksum, 0, address, data.length, 4);

	return Base58.encode(address);
}

參考

  1. bitcoinj
  2. Mastering Bitcoin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM