算法簡介
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')
"6j5iu4elnajlrrs4ugk5tjnd365b42csgh7b3hq"將編碼後的字符串根據地址屬性,
屬於測試網(t),
還是正式網(f),
是錢包地址(1)
是合約地址(2)
加上相應的前綴。
得到最終地址:
t16j5iu4elnajlrrs4ugk5tjnd365b42csgh7b3hq
下面是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))
/**
* 什麼是壓縮公鑰?
*
* 什麼是未壓縮公鑰?
*/
//未壓縮公鑰16進制
var pulStr =
"0x04" + ecKey.pubKeyPoint.affineXCoord.toString() + ecKey.pubKeyPoint.affineYCoord.toString()
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 = "0x01$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"
}