前一段时间看了区块链相关的内容,学习了一下bitcoin地址生成。内容来自网络。
第一步,随机选取一个32字节的数,大小介于1~0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141之间,作为私钥
PS: 助记词是将这个随机数按每 11位分组映射到 2048 个单词位得到 12 16 或 24 个单词。
18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725
第二步,使用椭圆曲线加密算法(ECDSA-SECP256k1)计算私钥所对应的非压缩公钥(共65字节,1字节0x04,32字节为x坐标,32字节为y坐标)。
0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
第三步,计算公钥的SHA-256哈希值
600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408
第四步,计算上一步哈希值的RIPEMD-160哈希值
010966776006953D5567439E5E39F86A0D273BEE
第五步,在上一步结果之间加入地址版本号(如比特币主网版本号”0x00”)
00010966776006953D5567439E5E39F86A0D273BEE
第六步,计算上一步结果的SHA-256哈希值
445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094
第七步,再次计算上一步结果的SHA-256哈希值
D61967F63C7DD183914A4AE452C9F6AD5D462CE3D277798075B107615C1A8A30
第八步,取上一步结果的前4个字节(8位十六进制数)D61967F6,把这4个字节加在第五步结果的后面,作为校验(这就是比特币地址的16进制形态)
00010966776006953D5567439E5E39F86A0D273BEED61967F6
第九步,用base58表示法变换一下地址(这就是最常见的比特币地址形态)
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 package main import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "fmt" "golang.org/x/crypto/ripemd160" "log" ) const VERSION = byte(0x00) const CHECKSUM_LENGTH = 4 type BitcoinKeys struct { PrivateKey *ecdsa.PrivateKey PublicKey []byte } func GetBitcoinKeys() *BitcoinKeys { b := &BitcoinKeys{nil, nil} b.newKeyPair() return b } func (b *BitcoinKeys) newKeyPair() { curve := elliptic.P256() var err error b.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader) if err != nil { log.Panic(err) } b.PublicKey = append(b.PrivateKey.PublicKey.X.Bytes(), b.PrivateKey.PublicKey.Y.Bytes()...) } //获取地址 func (b *BitcoinKeys) GetAddress() []byte { //1.ripemd160(sha256(publickey)) ripPubKey := GeneratePublicKeyHash(b.PublicKey) //2.最前面添加一个字节的版本信息获得 versionPublickeyHash versionPublickeyHash := append([]byte{VERSION}, ripPubKey[:]...) //3.sha256(sha256(versionPublickeyHash)) 取最后四个字节的值 tailHash := CheckSumHash(versionPublickeyHash) //4.拼接最终hash versionPublickeyHash + checksumHash finalHash := append(versionPublickeyHash, tailHash...) //进行base58加密 address := Base58Encode(finalHash) return address } func GeneratePublicKeyHash(publicKey []byte) []byte { sha256PubKey := sha256.Sum256(publicKey) r := ripemd160.New() r.Write(sha256PubKey[:]) ripPubKey := r.Sum(nil) return ripPubKey } //通过地址获得公钥 func GetPublicKeyHashFromAddress(address string) []byte { addressBytes := []byte(address) fullHash := Base58Decode(addressBytes) publicKeyHash := fullHash[1 : len(fullHash)-CHECKSUM_LENGTH] return publicKeyHash } func CheckSumHash(versionPublickeyHash []byte) []byte { versionPublickeyHashSha1 := sha256.Sum256(versionPublickeyHash) versionPublickeyHashSha2 := sha256.Sum256(versionPublickeyHashSha1[:]) tailHash := versionPublickeyHashSha2[:CHECKSUM_LENGTH] return tailHash } //检测比特币地址是否有效 func IsVaildBitcoinAddress(address string) bool { adddressByte := []byte(address) fullHash := Base58Decode(adddressByte) if len(fullHash) != 25 { return false } prefixHash := fullHash[:len(fullHash)-CHECKSUM_LENGTH] tailHash := fullHash[len(fullHash)-CHECKSUM_LENGTH:] tailHash2 := CheckSumHash(prefixHash) if bytes.Compare(tailHash, tailHash2[:]) == 0 { return true } else { return false } } func main() { keys := GetBitcoinKeys() bitcoinAddress := keys.GetAddress() fmt.Println("比特币地址:", string(bitcoinAddress)) fmt.Printf("比特币地址是否有效:%v\n:", IsVaildBitcoinAddress(string(bitcoinAddress))) }
base58 Base58 采用数字、大写字母、小写字母,去除歧义字符 0(零)、O(大写字母 O)、I(大写字母i)、l(小写字母L),总计58个字符作为编码的字母表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package main import ( "bytes" "math/big" ) var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") func Base58Encode(input []byte) []byte { var result []byte x := big.NewInt(0).SetBytes(input) base := big.NewInt(int64(len(b58Alphabet))) zero := big.NewInt(0) mod := &big.Int{} for x.Cmp(zero) != 0 { x.DivMod(x, base, mod) result = append(result, b58Alphabet[mod.Int64()]) } ReverseBytes(result) for _, b := range input { if b == 0x00 { result = append([]byte{b58Alphabet[0]}, result...) } else { break } } return result } func Base58Decode(input []byte) []byte { result := big.NewInt(0) zeroBytes := 0 for _, b := range input { if b != b58Alphabet[0] { break } zeroBytes++ } payload := input[zeroBytes:] for _, b := range payload { charIndex := bytes.IndexByte(b58Alphabet, b) result.Mul(result, big.NewInt(int64(len(b58Alphabet)))) result.Add(result, big.NewInt(int64(charIndex))) } decoded := result.Bytes() decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) return decoded } func ReverseBytes(data []byte) { for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { data[i], data[j] = data[j], data[i] } }