Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

放弃六月们
2386 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。( @  U$ Z8 d0 [& @3 i, Z
见 Account.swift 类:
! ~8 `2 _  B4 k7 @0 z2 }public init?() {$ g8 N* T% _3 D5 a- ?" d& d
        var pkeyData = Data(count: 32)  {; u- Y* p6 S, I8 e
        let result = pkeyData.withUnsafeMutableBytes {
+ R, m( p( [$ s- J            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
. `/ r: J% A$ e; X# O        }, S' u* g7 b, f& K& b% A/ |$ F4 A0 ^
        + U: M: [( P" C) T. r9 y; J( F% U
        if result != errSecSuccess {$ ~2 N( P' r( I
            fatalError()
+ W. G, o) g  O7 T        }2 z0 S- @( }4 b7 B7 ~/ T0 j1 w1 O
        
2 j3 M7 z2 d7 }9 }2 w        var error: NSError?
/ c, r/ w/ Q4 o+ M8 e  [        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
1 U1 \& v6 p9 y8 B        self.wif = wallet.wif(). {) c" y6 u7 M/ Q# f
        self.publicKey = wallet.publicKey()& C6 j3 D  n1 M! i! A
        self.privateKey = pkeyData
5 _1 c* s0 j' Q7 t- z        self.address = wallet.address()
" ?5 s& R9 v( H6 F* s        self.hashedSignature = wallet.hashedSignature()8 Q( ]$ }5 y; L$ o) x: V
        //default to mainnet
6 z3 a- o, e0 A* W- K) y! z5 ]        self.neoClient = NeoClient.sharedMain& d) J) U# f$ R. \$ [& K
    }
) Q% R, H! c. O. H; M; o它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:8 V- ?; d: i# V% i& \  D
/*!0 G. c/ r, z$ T1 b  A) R
     @function SecRandomCopyBytes
- L# e: p1 j3 y( o     @abstract Return count random bytes in *bytes, allocated by the caller.
" L: c4 b8 l4 w' |' t/ C" P        It is critical to check the return value for error
# q& \7 g3 }2 h0 K4 y& A. c     @result Return 0 on success, any other value on failure./ }8 v! U. D, V) x" k8 Y
*/  B1 g7 r0 }  \  k& o0 s; i
@available(iOS 2.0, *)
  C, d. _( _8 K" D2 Z4 }, X& ypublic func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32
2 ^! d' k, q$ }/ G! @& x随机生成一个32字节的 Data 数据,即 privatekeyData:8 Y& q( ?8 T! a5 q3 [$ q9 b. Y6 z$ x" ?3 k
var pkeyData = Data(count: 32)
. G9 _- v. O% u0 o        let result = pkeyData.withUnsafeMutableBytes {
% m6 u/ m4 H" l1 j3 f2 H            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)  X$ I  b1 S0 s
        }
- B8 Z: ~; C8 _然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:
/ X/ A  O- n  I3 }. G& t( j% Uvar error: NSError?
9 o- d0 b% Q8 q0 r4 g5 ?guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
# J% ]- g1 M! O* f5 f- X' h// Generate a wallet from a private key9 B; ?1 ]' M0 I2 \% u" v
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
- g- D1 }: V# v8 V3 g5 F5 s& C+ \5 ?    pb := hex2bytes(privateKey)6 |* I: w& Q/ F, b$ j
    var priv btckey.PrivateKey
4 o9 x, _3 w4 F, ~) A    err := priv.FromBytes(pb)7 n( e3 I! f2 a; {
    if err != nil {4 B2 p$ e. w: r3 F# [" ]8 B
        return &Wallet{}, err
9 @' e- T* \: q- z# c  d" H/ e    }
/ ^6 O1 Z  `- V+ [3 e; Q$ a    wallet := &Wallet{
2 q  T8 r4 z0 L) F0 u; Q$ @        PublicKey:       priv.PublicKey.ToBytes(),  c2 M# n* ?1 U, }1 p) Z6 _7 q+ i
        PrivateKey:      priv.ToBytes(),
2 {# L  p- {- Q) y! N        Address:         priv.ToNeoAddress(),( `7 U7 e( s6 X- f7 P. n
        WIF:             priv.ToWIFC(),4 M0 N% u- v9 q2 O
        HashedSignature: priv.ToNeoSignature(),
( d$ G7 D' N" k7 b    }% @/ W% {2 r* i" o8 ^1 Y& @
    return wallet, nil8 ?2 v7 `. G; x4 I1 m* e
}
/ X" Y( K- [8 a& i) R- l: J6 s" k5 j公钥是怎么来的?
$ J; i( L' c' y" y* V& ~1 a4 L; T, c公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。% x" {  B! v9 K! X
见neowallet.go 和 btckey.go:8 ^: Z/ {; y+ J  N$ p. b
// Generate a wallet from a private key
0 v1 H' v% U( Afunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {1 I. {  G, m5 U" C
    pb := hex2bytes(privateKey)
* e: k8 `9 r' w6 o: A5 H    var priv btckey.PrivateKey& j: a& _% D# C+ ~+ ~( i! k
    err := priv.FromBytes(pb)
2 v" S% m7 n) s* H/ r# r, _    if err != nil {
" m2 ]' H, A! ^" s9 K+ L        return &Wallet{}, err6 g( Y$ u, X7 V* e
    }0 m! \+ w) M. [% k, ~. q
    wallet := &Wallet{; n* W: ]7 L6 L/ l
        PublicKey:       priv.PublicKey.ToBytes(),' M. q! M; B1 A  C4 y' ~
        PrivateKey:      priv.ToBytes(),
6 _8 ]3 b, D8 q# s+ R        Address:         priv.ToNeoAddress(),2 A( y2 {- D' I1 T- e6 G4 d% {2 v" V
        WIF:             priv.ToWIFC()," T# {% `- v/ \) }6 d& w+ Y4 x
        HashedSignature: priv.ToNeoSignature(),
& b  z8 u" B* B  O% m/ m' H9 u: H    }8 O; b; r* b  O# _, i+ ^
    return wallet, nil! [  P) o* _( g) y5 R+ n
}/ @% ^$ k5 r+ a# M+ u
// derive derives a Bitcoin public key from a Bitcoin private key.
/ e- _: ~  K6 Hfunc (priv *PrivateKey) derive() (pub *PublicKey) {
9 ~7 Z' p2 V& |9 J+ [9 O. F1 u/ ]    /* See Certicom's SEC1 3.2.1, pg.23 */+ P% }7 b( j; R
    /* Derive public key from Q = d*G */4 k& W2 z' e; K2 C
    Q := secp256r1.ScalarBaseMult(priv.D)
6 o3 f6 {. S4 ^8 I  R) b    /* Check that Q is on the curve */9 P, h2 H8 ~+ q/ c; l' H
    if !secp256r1.IsOnCurve(Q) {4 x7 s0 C, s  ^# J5 p
        panic("Catastrophic math logic failure in public key derivation.")
! K: O2 |' N5 j# q1 l+ [9 {8 T    }
2 A; @) j( g+ L1 C3 M! `+ i    priv.X = Q.X- n* S" j: Q$ P+ p7 V
    priv.Y = Q.Y+ s% q: c2 c/ I) }2 ~  D; O
    return &priv.PublicKey4 t2 \2 D" g3 i0 O  s5 q
}, `  B3 t% A8 ]
地址脚本是怎么来的?
/ ]3 _" t+ X* D) S" H8 r2 d地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:% ^2 t- n' z  f" e# i
前面是:0x21后面是:0xAC8 i. Z) Y( J% q$ T
9 G3 z) m+ Q4 c# E! I
见btckey.go:
  b0 N$ `0 N% r( z# {9 {/ J# ~/* Convert the public key to bytes */
3 ]9 i5 X2 j! t, l8 P4 g    pub_bytes := pub.ToBytes()
. y. W+ w. @- Q  I$ P* v) C. C    pub_bytes = append([]byte{0x21}, pub_bytes...)
/ O7 y; g# }$ j( F5 F: V3 b- A    pub_bytes = append(pub_bytes, 0xAC)0 E: z6 T& w( F+ w2 H: m2 ?) B8 z
地址ScriptHash是怎么来的?4 v- J+ H+ I9 u
地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:
/ D0 L9 @  O/ ]4 V1 @% X见btckey.go:
( o$ d( \' N9 b& D/* SHA256 Hash */
7 }1 N' X# B" D+ K* R. q    sha256_h := sha256.New()
" r+ B2 O1 x8 g& Y3 w6 Q; O    sha256_h.Reset()
4 o6 m: K/ {5 m) I& B    sha256_h.Write(pub_bytes)
2 A0 B7 e) N  N    pub_hash_1 := sha256_h.Sum(nil)
+ t, k1 _4 R  @3 s7 D# g    /* RIPEMD-160 Hash */# Z. @) o0 A. A* w# h
    ripemd160_h := ripemd160.New()
4 n5 }* d) p+ I    ripemd160_h.Reset()
; O% O) e5 w0 b4 D    ripemd160_h.Write(pub_hash_1)
# \  b/ ?8 B$ R3 w, [. V    pub_hash_2 := ripemd160_h.Sum(nil)3 E4 c$ n  i; @" Z9 x' o
    program_hash := pub_hash_2
6 h8 v" s: D5 K4 V, B; W地址是怎么来的?
- Z8 `5 i4 N2 v3 E* l+ X地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:$ R) x8 T9 Z2 V
加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码8 G9 u( N6 F" `
! b" O( A- v3 D6 D
见 btckey.go 完整的由公钥生成地址的代码:
) g  P% A: A' z% n, M+ s// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string./ f8 m: X# P5 J1 s# ~  ]
func (pub *PublicKey) ToNeoAddress() (address string) {
. O% B' d+ B& _. [( g0 p) u* F* r    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */
. T2 b) N) a+ F    /* Convert the public key to bytes */3 I# [; m; V0 H' \* {
    pub_bytes := pub.ToBytes()
/ w5 z! j. V; Z: X- T0 L% ^    pub_bytes = append([]byte{0x21}, pub_bytes...)
) q% j0 x: v( D% q    pub_bytes = append(pub_bytes, 0xAC)
" j6 I1 M" D8 Q! g( a3 J# y3 u- T    /* SHA256 Hash */
4 I  j7 c, `+ T% O+ _1 J    sha256_h := sha256.New()
' }$ \) I6 g" r0 ^& h    sha256_h.Reset()
( b- s7 k" n4 Y& t    sha256_h.Write(pub_bytes)* f. ^* X) x' o# d6 i' N9 ?3 N# m* L( o
    pub_hash_1 := sha256_h.Sum(nil)
* ^* s+ T, h" k6 j3 k/ G    /* RIPEMD-160 Hash */8 Q7 r' o2 v' q& q$ C- z0 X, R
    ripemd160_h := ripemd160.New()4 Q, S  m% q% @
    ripemd160_h.Reset()- H+ \5 n" n1 d3 V2 X- p! W
    ripemd160_h.Write(pub_hash_1)
$ k. D+ U7 V% }  p+ v5 F    pub_hash_2 := ripemd160_h.Sum(nil)% F/ h4 r+ {) F2 e) P$ f9 L" @/ a
    program_hash := pub_hash_2
; i  C& `! z7 p    //wallet version0 {2 T& L- r, H  ]7 U; U
    //program_hash = append([]byte{0x17}, program_hash...)/ o1 T4 O2 ]! H' u6 h* c7 g/ [
    // doublesha := sha256Bytes(sha256Bytes(program_hash))5 }* ~  \# J% _. O' J
    // checksum := doublesha[0:4]
$ I5 }2 ^4 K1 G3 t( D: s) X    // result := append(program_hash, checksum...)
7 n& P! C$ d$ D, m; y: F# L( g    /* Convert hash bytes to base58 check encoded sequence */2 k: f$ C! _# D- t$ ^
    address = b58checkencodeNEO(0x17, program_hash)
9 K+ _5 [6 }+ Q    return address
% y& S9 ]4 h  c. _}
1 U, p. K, H# m// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.% b) |. Q; G/ o9 a
func b58checkencodeNEO(ver uint8, b []byte) (s string) {- i( c% u7 ?$ H% p- b
    /* Prepend version */3 |8 `) E" e  _. e7 d
    bcpy := append([]byte{ver}, b...)
( n$ A% H5 j% h1 [    /* Create a new SHA256 context */
7 k( M( y  [$ v- m    sha256_h := sha256.New()
5 a. }- S- |' u* O; ^" s' b6 B    /* SHA256 Hash #1 */
) O& ]" t8 ?0 c  u! Y    sha256_h.Reset()
6 T* ?( v7 j) E6 d$ v    sha256_h.Write(bcpy)+ T* ]; r! K! m+ R/ m* ~
    hash1 := sha256_h.Sum(nil)
- F; {; M8 p5 q& q2 H    /* SHA256 Hash #2 */
  j! X/ {$ S: \3 t- w* E    sha256_h.Reset()
) E3 X$ z0 W# {+ [$ Y5 i! q& @    sha256_h.Write(hash1), q; D  @8 k1 d, E! |
    hash2 := sha256_h.Sum(nil)
3 V. s, G+ f1 B# }7 p% N    /* Append first four bytes of hash */" _+ P$ I1 a1 A% P( E  ~  U
    bcpy = append(bcpy, hash2[0:4]...)
0 b+ A% I8 x$ n0 ]    /* Encode base58 string */0 b& U: w3 @4 n
    s = b58encode(bcpy)0 P% b# K; b& S& e4 I
    // /* For number of leading 0's in bytes, prepend 1 */
; n) o" v5 |: [; e* j6 {3 j- t: V    // for _, v := range bcpy {( l3 ]# M4 z  }7 ^7 Z
    //  if v != 0 {
5 _7 v' G4 V$ ]+ O6 X6 E4 S. Z$ ~) A- \    //      break
$ N6 F5 Q& E7 U6 O8 q    //  }
$ Z7 ~( j  D* }    //  s = "1" + s' ~6 Y) s% D8 u& r, a, q
    // }
$ y0 G- K4 Z8 v, _* g    return s0 P: ?0 ^# o& u/ ^3 [# v
}
/ B# f3 T' |: a5 G; c; _WIF 是怎么来的?
7 V2 q! j. a$ |8 }# F4 kWIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:
: F; G% s4 y6 S前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码. S7 s# N3 X: g$ d  X
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8