Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

一文弄懂:区块链钱包的私钥

放弃六月们
2390 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。
4 E! [: h' P' A" b8 [, W8 y7 K见 Account.swift 类:
4 E$ l! X$ `5 _" u  ypublic init?() {
4 M9 R" ^) c9 W2 I6 G        var pkeyData = Data(count: 32)
) w( E% U( d' [- Q% O7 o) N        let result = pkeyData.withUnsafeMutableBytes {* q3 X9 Z9 ?' y/ e
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
# C( T# X0 c6 @) D( r7 U        }
8 F0 m- |# W' V- R# W( O# B- p) h! B        
1 J  X+ Y3 k  p2 M5 u        if result != errSecSuccess {
+ }& G- L: ^0 f) I" P4 P            fatalError()
6 Y5 n! y$ R/ @. l. l  r& k; N        }" B. X0 D" L( m+ K% @; u- u
        # ~( u, T; E* C
        var error: NSError?
7 @; ?+ v" g% ]! R  {5 i        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
% n, Z# o' }: V+ P2 [6 s        self.wif = wallet.wif()
0 V) e8 _& ]5 v! j# l* F5 @. o% z        self.publicKey = wallet.publicKey()
3 ]- `/ \0 D7 K$ c. D        self.privateKey = pkeyData5 b1 Q( E; X7 q$ T) ]
        self.address = wallet.address()
2 V/ c3 p$ I! i2 L0 s        self.hashedSignature = wallet.hashedSignature(); M+ P/ J* E5 D
        //default to mainnet1 c1 ]) U: G2 A0 Y+ G4 r
        self.neoClient = NeoClient.sharedMain
$ e( v" O2 X6 H    }4 x, ^0 {5 r8 G  }2 N
它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:  U9 x5 G2 D8 R! E1 s# e) u4 F
/*!, x. l8 A1 Q. {) |  |
     @function SecRandomCopyBytes( i6 b! s7 ?7 I! d3 B) h( P
     @abstract Return count random bytes in *bytes, allocated by the caller.( P9 k7 T' h9 r+ m9 G
        It is critical to check the return value for error! L" G6 [' x( q& n$ S
     @result Return 0 on success, any other value on failure.' m% \- _0 n5 i; W3 y3 _0 _
*/- K  X& \0 j0 a, ]. Z! ?" n; N& Z* n
@available(iOS 2.0, *)5 ~7 \  v  t, X1 [- r8 |' _
public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32
" `+ Y6 o+ q$ k5 z& Q6 K$ |' G随机生成一个32字节的 Data 数据,即 privatekeyData:
: ]* ^5 c' D" F+ k  k# }var pkeyData = Data(count: 32)
! o! I! j0 T+ k/ C! I6 G. f        let result = pkeyData.withUnsafeMutableBytes {+ L* x8 j- @. K+ F  m
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
5 e- e6 ^4 i# @$ F2 |9 S        }4 m; t2 M" Q, t& Q0 n
然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:. I* m8 ~) f" V8 H3 b
var error: NSError?+ N  P* _; o' Z/ M  D' _
guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }, r6 _# J6 k( r% u1 P
// Generate a wallet from a private key9 {' G* V' R+ P0 L0 o( R
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {7 o$ D4 M/ j1 [0 l' r; _3 u
    pb := hex2bytes(privateKey)
2 X1 {  `" ~/ Y& j6 ?( M" n8 |5 v; ~  h    var priv btckey.PrivateKey! g( Y5 X/ c; l5 l5 L7 N( X
    err := priv.FromBytes(pb)
! ^, E& q, Q: C0 g* W    if err != nil {. G1 N% |' G& Y: ^. F
        return &Wallet{}, err
! [2 [% _/ ]4 p/ U. B. \8 ~3 m3 f& t    }' s( s' M, H5 ^0 z/ }
    wallet := &Wallet{+ w" {+ W. p; s* X4 h! n
        PublicKey:       priv.PublicKey.ToBytes(),2 }' {  T4 S9 y$ N: j1 m
        PrivateKey:      priv.ToBytes(),
! f4 M& j( m+ ^( ]" B  s        Address:         priv.ToNeoAddress(),
6 L( ?# g! X8 V' r        WIF:             priv.ToWIFC(),& A' K. K' S8 v8 g$ ]7 \" h& E
        HashedSignature: priv.ToNeoSignature(),
8 O" G0 R% Q' K8 J6 y) X- b    }
- ~( [1 g' j/ b1 y- ?+ d2 |3 e    return wallet, nil
8 c$ r, B; I' o% _- F+ \1 D}! Q0 I3 s+ S2 S5 ]
公钥是怎么来的?
6 C7 Y1 t' G  f9 T1 K公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。
  Q1 B- h: g, B. G见neowallet.go 和 btckey.go:- t) A! N( G0 T. a
// Generate a wallet from a private key
3 `. D( L9 m8 Qfunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {& E$ o+ W' u& H! b+ K- \4 Y0 \
    pb := hex2bytes(privateKey)
: Z7 H$ m) S/ q: u# y4 n8 Y    var priv btckey.PrivateKey
0 L9 @' W0 s9 `  l' x: e$ e    err := priv.FromBytes(pb)8 {- @5 ^& L' G& s' ?/ K& y
    if err != nil {" z( D3 w8 k9 H& a
        return &Wallet{}, err; ]) d: K/ r$ \6 k& k% X9 x! z
    }* O$ j. f$ m' |4 V4 ]
    wallet := &Wallet{6 T3 `/ J$ y0 K3 r6 [* w6 S
        PublicKey:       priv.PublicKey.ToBytes(),
' H6 t9 T6 q, J1 h1 \% D6 T  j) u        PrivateKey:      priv.ToBytes(),
! s6 S" \/ q- ?( n4 D        Address:         priv.ToNeoAddress(),
" p6 h0 ]5 G, E7 n        WIF:             priv.ToWIFC(),4 y) V. {# o0 r2 A9 h4 o6 D
        HashedSignature: priv.ToNeoSignature(),
9 K! Y$ ^) ?! e  F' Y    }8 l1 e7 L3 T# ~, F4 W1 ]6 N/ r$ m
    return wallet, nil) e: i- q0 v$ s% X, K7 T4 C
}
3 z# I% m2 g% B" ]// derive derives a Bitcoin public key from a Bitcoin private key./ t. Q2 l, y+ `( C; B9 p, ~8 E2 r
func (priv *PrivateKey) derive() (pub *PublicKey) {
( B% Y! W! w+ w/ w    /* See Certicom's SEC1 3.2.1, pg.23 */' G) S1 s% J  T/ c& u5 V* T
    /* Derive public key from Q = d*G */
' C! Y* _+ }$ S* J    Q := secp256r1.ScalarBaseMult(priv.D)
4 p2 o0 K0 \% k7 ?  e2 t    /* Check that Q is on the curve */, Q( J' X8 l3 Y! w8 u
    if !secp256r1.IsOnCurve(Q) {
, F: R3 F) }8 R2 f        panic("Catastrophic math logic failure in public key derivation.")
) {7 F% d; B+ u# n    }
" C, D' ~' ?# i4 _    priv.X = Q.X& V. u# Z$ G5 G1 t, b7 S/ i
    priv.Y = Q.Y
# V) o. G1 g/ F, K" T    return &priv.PublicKey
3 u# B  b. N: Z0 x% G) h}
( d' b- O) g# u地址脚本是怎么来的?
' k7 O4 m$ n  k. V# G地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:! p- n9 n, V7 j
前面是:0x21后面是:0xAC
3 b0 B2 A% k7 I- c% Z& M. J
2 M: ]" e. [5 z; k5 ~+ i! {+ ^
见btckey.go:
& y! y% @8 I5 E, c( M/* Convert the public key to bytes */
! K, k1 y4 L+ _1 J7 Z& w2 `) N3 v% V* t    pub_bytes := pub.ToBytes(), I* w9 O' \8 o8 A0 t( L
    pub_bytes = append([]byte{0x21}, pub_bytes...)
+ t, P8 n& P( M% O    pub_bytes = append(pub_bytes, 0xAC). K0 A( b8 y" B; B$ V
地址ScriptHash是怎么来的?
+ [$ b4 P% A* t% ~地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:1 L9 S$ h1 _; c, l
见btckey.go:' L- q6 m) d9 S1 o8 I! W
/* SHA256 Hash */- V! `: g: e( ~! G1 c
    sha256_h := sha256.New()
8 }/ W1 X5 S$ t# M6 e1 G. T    sha256_h.Reset()9 c& r$ v# t$ y
    sha256_h.Write(pub_bytes)
& p% T5 l' K9 X. z+ o    pub_hash_1 := sha256_h.Sum(nil)
# y2 W$ x1 W( Q% B+ _' a    /* RIPEMD-160 Hash */3 _3 h5 s: w# w, b' Z  z! ]/ e. i
    ripemd160_h := ripemd160.New()
& c+ {  k- Y3 j% L7 z0 Z    ripemd160_h.Reset()
' L+ p8 g6 O2 \' P' U    ripemd160_h.Write(pub_hash_1)" N$ `' {# K! _) Y
    pub_hash_2 := ripemd160_h.Sum(nil)0 N& r; g- P- U/ w0 d. @. P1 N; Z
    program_hash := pub_hash_2
' j$ s% L+ u* o9 [9 j" v- S地址是怎么来的?
* j" e; @2 ?; e/ m4 g7 J4 W$ n地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:" N: L  L/ [" l# ]( g( N( D
加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码4 ~8 w! E6 f" f0 w1 j, }
8 g4 q1 G( |2 l7 {& V
见 btckey.go 完整的由公钥生成地址的代码:0 X- W' f% }; }$ N; F: P
// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.3 q' L$ Q% B/ r! d* |" O8 x4 S
func (pub *PublicKey) ToNeoAddress() (address string) {
% a1 t- z7 L: O7 C- a5 X    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */" ~" z2 z+ l( X+ X! c
    /* Convert the public key to bytes */
( \: q& L1 [4 ?0 V7 y9 \* U$ q    pub_bytes := pub.ToBytes()
2 Q# q* w+ l& H+ C3 a    pub_bytes = append([]byte{0x21}, pub_bytes...), R3 `# N- \$ W- P; K8 O: A9 O
    pub_bytes = append(pub_bytes, 0xAC)1 W% u9 K* K/ I" O
    /* SHA256 Hash */8 f' e, ?( j+ O/ o0 Y  i/ z
    sha256_h := sha256.New()
5 i5 n$ w9 |; W# l( L    sha256_h.Reset()
! |- f& q8 O2 k% ?, i) C, q  f    sha256_h.Write(pub_bytes)0 L1 J. x! H) u* c5 H7 x. U- e
    pub_hash_1 := sha256_h.Sum(nil)) U' U  Q& m$ `% K
    /* RIPEMD-160 Hash */' ^3 s, s2 H  d. f7 O
    ripemd160_h := ripemd160.New()  b& S6 A6 g4 d
    ripemd160_h.Reset()
3 u4 |; r7 T; A$ E- n7 t/ P# v    ripemd160_h.Write(pub_hash_1)$ h% U5 V2 B  M
    pub_hash_2 := ripemd160_h.Sum(nil)
4 R4 l( x) I: f    program_hash := pub_hash_2
2 g0 e0 g1 F1 [' y& _' i- e    //wallet version2 L/ ~6 u4 p) O2 L0 v
    //program_hash = append([]byte{0x17}, program_hash...)# Q! w! |3 ]% T
    // doublesha := sha256Bytes(sha256Bytes(program_hash))) {. \2 j( I: x3 @! i
    // checksum := doublesha[0:4]
7 R+ x: o9 f: |0 V, g" p    // result := append(program_hash, checksum...)) f4 ?# K  ?+ `( q; P
    /* Convert hash bytes to base58 check encoded sequence */2 Y: G3 t- ]1 o: F" U, ~' x
    address = b58checkencodeNEO(0x17, program_hash)8 h7 R) J0 a# k
    return address
; f  J1 G* z  |' Z! r1 X% B}
( I  _' V; y* k' f. n' V1 ]/ i// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string., {  M4 X( l5 \5 I+ f( Q+ @3 |! |
func b58checkencodeNEO(ver uint8, b []byte) (s string) {
1 K2 i4 Q6 _! p) @7 T, F8 m8 o    /* Prepend version */
1 k. Z- T* }" T+ ], z* g    bcpy := append([]byte{ver}, b...)( l# Y1 G7 W( D5 A* _; p3 j
    /* Create a new SHA256 context */6 l: y- g9 c$ H7 U9 W
    sha256_h := sha256.New()
, O+ U7 T) G/ q, y$ j4 r7 ]% ~    /* SHA256 Hash #1 */
* P3 X  m! ^0 g0 q( A, g    sha256_h.Reset()
3 V7 O: k9 R, X% h( z( D( a    sha256_h.Write(bcpy)+ @# l" ~9 @9 m, V% f- T
    hash1 := sha256_h.Sum(nil)) z5 [/ I  L* t: L4 O) u
    /* SHA256 Hash #2 */
- d* c* }% B3 Q; g' M    sha256_h.Reset()$ N( H$ Y$ J" j4 z/ F
    sha256_h.Write(hash1)
# {3 O& \. ?! |3 g7 U0 V, J    hash2 := sha256_h.Sum(nil)1 J; {; U" }+ u; f2 h; |" {% w
    /* Append first four bytes of hash */3 c9 S8 M; I3 x/ n* q- G" i- U2 Q
    bcpy = append(bcpy, hash2[0:4]...)
0 c  d2 C6 X) u2 s! `# s4 c    /* Encode base58 string */
7 [4 P2 T9 L" h& F/ \    s = b58encode(bcpy)
4 G( m* x6 {8 c3 e% b: j1 M  _6 G3 c    // /* For number of leading 0's in bytes, prepend 1 */* }& S; w/ c: R8 o7 F1 ], R
    // for _, v := range bcpy {$ Z! i8 q) i1 [3 d/ j3 R+ ~
    //  if v != 0 {# c6 E% G" _- n% \% T2 D
    //      break0 [$ r3 x& \) d/ H" i
    //  }
% ~5 ?, |. t1 M    //  s = "1" + s4 Z8 U1 {  L+ X# p( D. x  J
    // }
$ C6 F$ G$ d, b4 _4 A# o    return s; o+ `3 H" A7 {7 T/ O8 s) k
}
8 q" r' I8 a8 u! M( z; P, V3 W. zWIF 是怎么来的?0 P& \! z  X, g" x
WIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:! \& b9 o8 T2 c2 P
前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码- P2 b# g# ?0 M5 Q7 b& R0 f
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8