算法简介
blake2
BLAKE2的定位是目前安全系数最高的哈希函数。BLAKE2是基于BLAKE实现的,BLAKE是2008年被提交至SHA-3竞赛的一种哈希函数。
BLAKE2不仅仅只是一个简单的哈希函数而已!首先,BLAKE2有两大主要版本:BLAKE2b和BLAKE2s。BLAKE2b是BLAKE的64位版本,它可以生成最高512位的任意长度哈希。BLAKE2s是BLAKE的32位版本,它可以生成最高256位的任意长度哈希。
BLAKE2x是对BLAKE2的简单扩展,它可以生成任意长度的哈希值(长度不受限制)。
ECC
椭圆曲线加密算法,即:Elliptic Curve Cryptography,简称ECC,是基于椭圆曲线数学理论实现的一种非对称加密算法。相比RSA,ECC优势是可以使用更短的密钥,来实现与RSA相当或更高的安全。据研究,160位ECC加密安全性相当于1024位RSA加密,210位ECC加密安全性相当于2048位RSA加密。
Base32编码
Base32编码是使用32个可打印字符(字母A-Z和数字2-7)对任意字节数据进行编码的方案,编码后的字符串不用区分大小写并排除了容易混淆的字符,可以方便地由人类使用并由计算机处理。Base32将任意字符串按照字节进行切分,并将每个字节对应的二进制值(不足8比特高位补0)串联起来,按照5比特一组进行切分,并将每组二进制值转换成十进制来对应32个可打印字符中的一个。
RFC
Request For Comments(RFC),是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。目前RFC文件是由Internet Society(ISOC)赞助发行。基本的互联网通信协议都有在RFC文件内详细说明。RFC文件还额外加入许多在标准内的论题,例如对于互联网新开发的协议及发展中所有的记录。因此几乎所有的互联网标准都有收录在RFC文件之中。
地址生成步骤:
随机生成256位私钥(BIP44协议,)
privateKey = generatePrivateKey()
"0x81232f16fa8f8bc2d31096d2407d9e392c25f048861a0e0f640f4febb4f22996"利用椭圆曲线加密算法生成公钥
publicKey=ECC.getPublicKeyFromPrivateKey(privateKey)
"0xeb15c814543f9c1e62f1e4e13e2b5fd2a4d224b58f8cfeb1e587378d46a96c06dfaf876bc176911e7613c3e8ffe1e928025e266918a935fc6bd921606fcca5b3"将公钥前加入0x04值后,进行20位的blake2b计算
blake2Hash = blake2b("0x04eb15c814543f9c1e62f1e4e13e2b5fd2a4d224b58f8cfeb1e587378d46a96c06dfaf876bc176911e7613c3e8ffe1e928025e266918a935fc6bd921606fcca5b3", 20)
"0x50cedfe81c8cdcf03fede2d075db9025d7f09463"将得到的blake2哈希值前添加0x01后,继续用blake2b算法计算4位校验和。
checksum = blake2b("0x0150cedfe81c8cdcf03fede2d075db9025d7f09463", 4)
"0x62c27772"(4位转16进制就是8个字符)将20位公钥哈希值和4位校验和连接起来,并用遵照RFC4648标准的Base32编码格式进行编码。
sourceAddress = Base32Encode(blake2Hash ,checksum, 'RFC4648')
"kdhn72a4rtopap7n4lihlw4qexl7bfddmlbho4q"将编码后的字符串根据地址属性,
属于测试网(t),
还是正式网(f),
是钱包地址(1)
是合约地址(2)
加上相应的前缀。
得到最终地址:
t1kdhn72a4rtopap7n4lihlw4qexl7bfddmlbho4q
下面是kt的代码:
//通过助记词得到种子
val seed = DeterministicSeed(
mnemonicCodes,
NumericUtil.toSeed(mnemonicCodes, ""),
"",
creationTimeSeconds
)
//通过biP44得到path
val path: String? = getPath(0)
//主密钥
val keyChain = DeterministicKeyChain.builder().seed(seed).build()
var rootPublicKey = keyChain.rootKey?.publicKeyAsHex
Log.d(TAG, "主公钥:$rootPublicKey")
val parent =
keyChain.getKeyByPath(BIP44Util.generatePath(path), true)
var p = Blake2b.Param()
p.digestLength = 20
//子私钥
var xprv = parent.privateKeyAsHex
Log.d(TAG, "子私钥:$xprv")
Log.d(TAG, "子私钥(Base58):" + Base58.encode(parent.privKeyBytes))
//
val ecKey: ECKey =
ECKey.fromPrivate(NumericUtil.hexToBytes(xprv), false)
/**
* 什么是压缩公钥?
*
* 什么是未压缩公钥?
*/
//未压缩公钥16进制
var pulStr =
ecKey.publicKeyAsHex
Log.d(TAG, "未压缩公钥:$pulStr")
//未压缩公钥字节
val encryptionKey =
NumericUtil.hexToBytes(pulStr)
//将公钥前加入0x04值后,进行20位的blake2b计算
p.digestLength = 20
var blake2Hash = Blake2b.Digest.newInstance(p)
var blake2HashHexByte = blake2Hash.digest(encryptionKey)
var blake2HashHexStr = NumericUtil.bytesToHex(blake2HashHexByte)
Log.d(TAG, blake2HashHexStr)
//将得到的blake2哈希值前添加0x01后,继续用blake2b算法计算4位校验和
var blake2HashSecond = "01$blake2HashHexStr"
//用blake2b算法计算4位校验和
p.digestLength = 4
var blake2b3 = Blake2b.Digest.newInstance(p)
var checksumBytes = blake2b3.digest(NumericUtil.hexToBytes(blake2HashSecond))
var checksum =
NumericUtil.bytesToHex(checksumBytes)
Log.d(TAG, "校检和:$checksum")
//将20位公钥哈希值和4位校验和连接起来
val addressBytes = ByteArray(blake2HashHexByte.size + checksumBytes.size)
System.arraycopy(blake2HashHexByte, 0, addressBytes, 0, blake2HashHexByte.size)
System.arraycopy(checksumBytes, 0, addressBytes, blake2HashHexByte.size, checksumBytes.size)
var address = "t1" + Base32New.encode(addressBytes)
Log.d(TAG, "地址:$address")
}
//m/44'/461'/0/0/0
private fun getPath(index: Int): String? {
//146或1
return "m/44'/461'/$index/0/0"
}
这个看路径如果不同生成地址也是不一样的。
//m/44'/461'/0/0/0
//m/44'/461'/0'/0/0
private fun getPath(index: Int): String? {
//146或1
return "m/44'/461'/$index/0/0"
}