如何判断比特币地址是否合法
判断一个给定的比特币地址是否合法,其实就相当于把流程倒推一下进行校验就好。
- 把地址 base58 解码成数组
- 把数组分成两个数组,数组一是地址校验和,数组二是地址的公钥哈希
- 地址的公钥哈希两次 Sha256 Hash
- 两次 Sha256 后的前 4 位,跟数组一比较。判断校验和是否相等(判断 1)
- 校验通过的解码,获取版本号
- 判断版本号(判断 2)
校验比特币地址的代码
isBitcoinAddress(address) {
try {
// 第10步:base58解码
const arr = bs58.decode(address);
const buf = Buffer.from(arr);
console.log(arr);
// 第9步:分成两个字节数组
const checksum = buf.slice(-4);
const bytes = buf.slice(0, buf.length - 4);
console.log(checksum.toString(`hex`));
console.log(bytes.toString(`hex`));
// 第6步(SHA256)
const shax1 = crypto.createHash(`sha256`).update(bytes).digest();
console.log(shax1.toString(`hex`));
// 第7步(SHA256)
const shax2 = crypto.createHash(`sha256`).update(shax1).digest();
console.log(shax2.toString(`hex`));
// 第8步.取校验和
const newChecksum = shax2.slice(0, 4);
// 校验和跟字节数组[checksum]比较。如果相同校验通过。
if (checksum.toString('hex') !== newChecksum.toString('hex')) {
throw new Error('Invalid checksum');
}
// 第5步.比特币主网版本号
const version = buf.toString('hex').slice(0, 2);
console.log(version);
// 检验版本号的合法性(主网00)00 为普通地址,05为脚本地址,注意大小写。
if (version !== '00' && version !== '05') {
throw new Error('Invalid version');
}
} catch (e) {
return false;
}
return true;
}
最终的比特币地址的创建和校验测试
"use strict";
const crypto = require('crypto');
const bs58 = require(`bs58`);
let utility = {
// 生成比特币地址
createBitcoinAddress() {
// 第1步
let privateKey = crypto.randomBytes(32);
// Test
// let privateKey = Buffer.from('18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725', 'hex');
// 第2步
let ecdh = crypto.createECDH('secp256k1').setPrivateKey(privateKey);
let cpublicKey = Buffer.from(ecdh.getPublicKey('hex', 'compressed'), 'hex');
// 第3步
let sha1 = crypto.createHash('sha256').update(Buffer.from(cpublicKey, 'hex')).digest();
// 第4步
let pubkeyHash = crypto.createHash('ripemd160').update(sha1).digest();
// 第5步: 添加 Version
const version = Buffer.from([0x00]);
let extendedPriKey = Buffer.alloc(version.length + pubkeyHash.length);
extendedPriKey = Buffer.concat([version, pubkeyHash], extendedPriKey.length);
// 第6步: 将 ECDSA_PublicKey_SHA256_RIPEMD160 进行第1次 SHA256 计算
let sha2 = crypto.createHash(`sha256`).update(Buffer.from(extendedPriKey, 'hex')).digest();
// 第7步: 将第6步的结果进行第2次 SHA256 计算
let sha3 = crypto.createHash('sha256').update(sha2).digest();
// 第8步: 取第二次 SHA256Hash 结果的前 4 个字节(这是地址的校验和)
let checksum = Buffer.alloc(4);
sha3.copy(checksum, 0, 0, checksum.length);
// 第9步: 计算
let btcAddress = Buffer.alloc(extendedPriKey.length + checksum.length);
btcAddress = Buffer.concat([extendedPriKey, checksum], btcAddress.length);
// 第10步: base58
let address = bs58.encode(btcAddress);
return {
address,
privateKey: privateKey.toString(`hex`)
};
},
// 校验地址是否合法
isBitcoinAddress(address) {
try {
// 第10步:base58解码
const arr = bs58.decode(address);
const buf = Buffer.from(arr);
console.log(arr);
// 第9步:分成两个字节数组
const checksum = buf.slice(-4);
const bytes = buf.slice(0, buf.length - 4);
console.log(checksum.toString(`hex`));
console.log(bytes.toString(`hex`));
// 第6步(SHA256)
const shax1 = crypto.createHash(`sha256`).update(bytes).digest();
console.log(shax1.toString(`hex`));
// 第7步(SHA256)
const shax2 = crypto.createHash(`sha256`).update(shax1).digest();
console.log(shax2.toString(`hex`));
// 第8步.取校验和
const newChecksum = shax2.slice(0, 4);
// 校验和跟字节数组[checksum]比较。如果相同校验通过。
if (checksum.toString('hex') !== newChecksum.toString('hex')) {
throw new Error('Invalid checksum');
}
// 第5步.比特币主网版本号
const version = buf.toString('hex').slice(0, 2);
console.log(version);
// 检验版本号的合法性(主网00)00 为普通地址,05为脚本地址,注意大小写。
if (version !== '00' && version !== '05') {
throw new Error('Invalid version');
}
} catch (e) {
return false;
}
return true;
}
}
// 创建
let newAddress = utility.createBitcoinAddress();
console.log('创建:比特币地址', newAddress);
// 校验
console.log('校验:比特币地址', utility.isBitcoinAddress(newAddress.address));
运行结果如下
创建:比特币地址 {
address: '1Bskdmqj8pJfugmZ7xw6Kc5YFjfsyCnneS',
privateKey: '49550d988169a6c55bb49f3c030b4a9965aac2cf274dbaa8e5950c666b129c3a'
}
<Buffer 00 77 4a 7a d2 57 70 03 4e 63 84 c8 35 27 18 5e d0 a6 af ad be bb dc 85 07>
bbdc8507
00774a7ad25770034e6384c83527185ed0a6afadbe
e7ed049416f21aa61b8587284c7337e9ad4a0533ed24d0e2b89019347bb8133f
bbdc8507021152b4e2e67d85eb9953efd97cf629a5a76f98d1234207157146f5
00
校验:比特币地址 true
通过测试,完美运行。