Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

放弃六月们
2332 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。
7 m& p! j0 E/ c4 j. Y, v见 Account.swift 类:
# f' Q6 p% g' y: U1 ^% b+ Vpublic init?() {1 k3 u0 D7 Y1 G% i) e
        var pkeyData = Data(count: 32)
9 X8 P/ G7 G0 D9 V        let result = pkeyData.withUnsafeMutableBytes {3 A8 P+ _6 X2 @$ U
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
. v+ v. f, [8 N; N% N5 `& {        }; r  t' ^3 a9 K
          e: z, a5 w* B
        if result != errSecSuccess {
$ F! p5 A% V3 d8 R3 ^8 M            fatalError()
6 J. _5 n0 ~; l& |        }* _, V) e5 y+ G. Y' I
        . A5 I  u  E& k
        var error: NSError?( |& C4 D2 Z. D& k$ E
        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }. D$ Z+ P0 i. A2 {$ q  d
        self.wif = wallet.wif()
. m0 m" t$ F5 t: g$ K* p7 }6 L7 F        self.publicKey = wallet.publicKey(): ^8 T0 a7 {" a7 F! u
        self.privateKey = pkeyData2 T- M: t9 ^% W) a8 F; F4 Y7 b, Q
        self.address = wallet.address()
9 A, s: b" e5 _        self.hashedSignature = wallet.hashedSignature()# Y$ u: ]9 f+ o2 f$ Y9 l
        //default to mainnet! F6 E# s: _2 `3 E
        self.neoClient = NeoClient.sharedMain
* y4 O6 z/ P9 ^2 Q% Y    }
2 ]0 m4 E2 j5 c0 v6 c1 E它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:
8 c  q1 h. q2 s$ W8 z/ D/*!  y8 ?. A$ @3 n7 o' x7 W( o9 Y  a
     @function SecRandomCopyBytes: Q; `4 d* m- f* x$ F0 @: ?
     @abstract Return count random bytes in *bytes, allocated by the caller.
. U$ |" m' h# B, I8 p& b        It is critical to check the return value for error
& N$ E8 \" x0 z. O( e     @result Return 0 on success, any other value on failure.7 l9 @* @0 |: l7 N# V: J$ |
*/4 [/ G& M8 U3 H
@available(iOS 2.0, *)
$ b( ~; ?) ]! C4 ]( `public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32: a) n, ~  ~" J# c5 F( w. m, Y
随机生成一个32字节的 Data 数据,即 privatekeyData:
3 H/ `" n& i0 Q3 p  d6 {: ^var pkeyData = Data(count: 32)
0 l* ?4 H: c6 A1 M        let result = pkeyData.withUnsafeMutableBytes {7 t$ l5 l( P" B+ i
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
$ X- c% U. L) x3 K# _0 j        }
8 G/ N  Q) A5 K) J7 s! I' a( r然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:
8 I$ v3 w4 a- nvar error: NSError?
' {) E2 d, h' E8 m# L) a+ Lguard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
1 D' r, ~+ h& N4 w// Generate a wallet from a private key# u6 F' B/ I6 H4 I5 x
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {, y# o0 g) b! j* R  U
    pb := hex2bytes(privateKey)
8 f$ r/ F& l1 ~6 E7 T    var priv btckey.PrivateKey
4 s4 k3 z& X4 }. z5 i: X4 x6 c* n    err := priv.FromBytes(pb)# U2 D& t; ^6 s. [; S
    if err != nil {
% h9 o& z0 J% Q+ e9 }        return &Wallet{}, err
5 N8 Y! |( m6 x0 ~4 ]" V    }
$ [* Z0 P4 c/ _5 Y    wallet := &Wallet{
* z7 V) P3 I. ~% c5 `        PublicKey:       priv.PublicKey.ToBytes(),
* W: E3 l' o! W5 J        PrivateKey:      priv.ToBytes(),9 n1 C& t* S, J# m9 j% |: [
        Address:         priv.ToNeoAddress(),
8 K! J0 K3 I8 |* ^: }$ M4 g$ s! \3 i        WIF:             priv.ToWIFC(),% l% `/ U, i- U8 E: {
        HashedSignature: priv.ToNeoSignature(),# c, Y4 I, i3 f6 y) `0 S+ ?8 R
    }- K8 i/ o, @: e8 v5 k" L! n
    return wallet, nil- Q0 w1 y8 X: w* v0 Z
}2 T. \! e/ _3 k5 L  V
公钥是怎么来的?) K( a* Y/ A' ]7 [  @
公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。! ?+ _( A2 `6 v1 }
见neowallet.go 和 btckey.go:
0 y) \& i' N, A' H+ P7 ~// Generate a wallet from a private key
  H6 |% f" E' Y. Z: b/ w& r6 pfunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {9 Q/ u7 X8 V9 I. n% N
    pb := hex2bytes(privateKey)$ Z$ ?" i; G& l1 p+ P# P
    var priv btckey.PrivateKey. ?2 b9 z* y( S2 H6 o
    err := priv.FromBytes(pb)
2 C1 s" s, @3 e2 [; N2 Z$ U2 b' M    if err != nil {8 Z. Z. \: x8 x# @& r6 [5 x
        return &Wallet{}, err# J* r, D/ B% `" |
    }
8 A9 W* l$ s" ^7 i    wallet := &Wallet{
  T; W* B4 K2 [; Q$ J: }        PublicKey:       priv.PublicKey.ToBytes(),2 [  Z0 {5 x! V/ k
        PrivateKey:      priv.ToBytes(),: H% B, @9 N  f: V: A4 S$ T+ _
        Address:         priv.ToNeoAddress(),
, B8 f0 ]( v1 v. R6 E; c        WIF:             priv.ToWIFC(),
+ {/ f" {/ }6 S1 y3 Q        HashedSignature: priv.ToNeoSignature(),
8 ?+ `% H2 V$ L& y9 p    }
; P( L3 q7 t1 ~* g1 \    return wallet, nil
) i1 R( q5 ^1 s9 _}9 m7 I6 M+ ~- F
// derive derives a Bitcoin public key from a Bitcoin private key." v8 K4 a2 W( y- g! E
func (priv *PrivateKey) derive() (pub *PublicKey) {
: G& ]4 R2 A- L4 ^7 X  n    /* See Certicom's SEC1 3.2.1, pg.23 */% ]3 j- F: ?2 t: P( @3 b# {0 N
    /* Derive public key from Q = d*G */
# h6 k/ U% U8 T& D- G8 X( m/ M/ j    Q := secp256r1.ScalarBaseMult(priv.D)
: R4 ]5 `* W) f8 K$ ~. \9 \; |$ q    /* Check that Q is on the curve */
( p6 R4 ~# X9 y- d- T$ F    if !secp256r1.IsOnCurve(Q) {7 x- J- [' ]! m# k
        panic("Catastrophic math logic failure in public key derivation.")
) W$ n, [, A0 X. q  j; t9 E    }/ j5 e) V4 {# W3 c) ]
    priv.X = Q.X& Q) h, G1 T3 d- n- Q
    priv.Y = Q.Y
# c2 `) p; }! X    return &priv.PublicKey* d: N3 R- P; I; C# h" q9 ?
}
; t+ O* ?0 B. [% _2 o) L地址脚本是怎么来的?+ \6 e7 Z. O! P; j  ?8 R
地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:5 v: ^( s! Z0 J. Q8 {
前面是:0x21后面是:0xAC( h* j' d& O, q. D8 T) n( ?% H
6 q8 z* ?/ k6 Q3 s
见btckey.go:
. H/ ^; H) g1 G' e. ]/* Convert the public key to bytes */
, E  E2 Q9 b+ C9 ?8 |( B    pub_bytes := pub.ToBytes()+ R4 [( M& ]2 D& H$ d* c
    pub_bytes = append([]byte{0x21}, pub_bytes...)
% L) i9 z8 ~# `3 F& C5 ^# X    pub_bytes = append(pub_bytes, 0xAC)0 c5 j. A3 d! D" H$ ~" w
地址ScriptHash是怎么来的?
* s$ `3 g& t: j: _地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:
6 }: m0 C4 q* E* g; D见btckey.go:
3 k2 F+ |* ~# [0 Q+ j, [$ _' U/* SHA256 Hash */& O8 y3 c/ G1 i: H4 V" c& _
    sha256_h := sha256.New()
. K% m$ t, F) j" c9 B    sha256_h.Reset()
/ `1 ~  O( x5 T+ S$ x2 D    sha256_h.Write(pub_bytes); F$ F/ v5 ]; v5 y' J/ l# w$ H5 S
    pub_hash_1 := sha256_h.Sum(nil)" Y! {9 T/ ^- a" x
    /* RIPEMD-160 Hash */7 c" ]0 h" o' s9 {
    ripemd160_h := ripemd160.New()
& z& x! V0 d) Y    ripemd160_h.Reset()
* ~% v' c2 t; Z  D! ?7 c  h    ripemd160_h.Write(pub_hash_1). @3 i9 c! I( ]% v/ }! A& Z1 H
    pub_hash_2 := ripemd160_h.Sum(nil)
* s5 E0 r. |1 W4 i6 e    program_hash := pub_hash_22 u; R2 D* _, B7 A* N8 H$ r
地址是怎么来的?+ L5 E, `0 C2 V8 Q; H4 k  O/ x" G
地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:
. F* I0 U0 ^! S0 Z加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码+ l- m2 X$ H- s0 W
; k3 Q& Q2 Y3 C+ r9 j- H/ }5 \
见 btckey.go 完整的由公钥生成地址的代码:
% e8 @  e$ v' R# ?// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.
, H$ i8 A4 _5 y- Y2 i, S) sfunc (pub *PublicKey) ToNeoAddress() (address string) {
0 w, F" ]  n7 _' L' R    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */; I4 X" U' ?8 r* S: A
    /* Convert the public key to bytes */4 H, H/ q+ W, a
    pub_bytes := pub.ToBytes()
- U& X9 M: S7 O    pub_bytes = append([]byte{0x21}, pub_bytes...)& Q; A# ~, w3 m, ?! p. |( Z2 {- v
    pub_bytes = append(pub_bytes, 0xAC)$ Q1 k- [+ Q8 X
    /* SHA256 Hash */
7 p" E* z; V, J- q4 y    sha256_h := sha256.New()6 H  U% |7 o+ I0 B# B
    sha256_h.Reset()/ A8 Z2 g7 U; a. G- T  I4 L+ X
    sha256_h.Write(pub_bytes)
* a, y% M- B: r( q' u- G" ~$ t    pub_hash_1 := sha256_h.Sum(nil); W' Q1 C! S& O4 ~* Q
    /* RIPEMD-160 Hash */. g0 z" D9 ^9 o9 |. i1 l- R# A
    ripemd160_h := ripemd160.New()1 L! i* ~' @$ G  K$ w
    ripemd160_h.Reset()) z; d2 D8 B0 P. `+ @8 y. z9 |9 h
    ripemd160_h.Write(pub_hash_1)
; ^3 Q' J3 P6 U) g0 d( Y    pub_hash_2 := ripemd160_h.Sum(nil)
/ n  B! }% E5 I' x6 E  ~    program_hash := pub_hash_2& N. }  E2 g& g# m' [
    //wallet version
4 o. U' _; @0 f4 Y8 X7 J/ k+ u7 ]+ V    //program_hash = append([]byte{0x17}, program_hash...)
& O% R; H5 q) r, ~* P    // doublesha := sha256Bytes(sha256Bytes(program_hash))
( m9 L! \- I# z4 A/ J4 G    // checksum := doublesha[0:4]8 j" O3 f1 O. A4 c  ?8 S
    // result := append(program_hash, checksum...)
. S3 L2 l7 Z, c; l    /* Convert hash bytes to base58 check encoded sequence */
$ I6 ^, G) @! q% D' j    address = b58checkencodeNEO(0x17, program_hash)
! s% w- }: p4 q0 s# T# Y" j, g5 r    return address
$ k* `- u1 L1 m  U7 K. O2 E, v- ^}/ `0 a: E  [& B7 m3 Y5 _
// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.
5 d% X* l6 V  A: D3 Rfunc b58checkencodeNEO(ver uint8, b []byte) (s string) {0 u0 ]: r/ Q5 L- d2 i
    /* Prepend version */' f( N. X! q. k
    bcpy := append([]byte{ver}, b...)
2 p. ~* S6 h7 y9 _5 w    /* Create a new SHA256 context */
1 y) B0 P9 k( }4 Q! _' [    sha256_h := sha256.New()* L* [3 C4 P7 L2 @
    /* SHA256 Hash #1 */
) x' j' V! K/ H0 e6 L( O! E    sha256_h.Reset()- e1 W9 D3 }( `2 U6 ?$ o" G( L  p
    sha256_h.Write(bcpy)+ h8 _. J+ @! N/ r
    hash1 := sha256_h.Sum(nil)4 e) L9 N/ q' X8 e- _
    /* SHA256 Hash #2 */9 Y! v  B" ^6 O3 m$ c. [
    sha256_h.Reset()+ ]6 {5 \" d* N, H( v
    sha256_h.Write(hash1)
! n) `: m: |; Y- I    hash2 := sha256_h.Sum(nil)
0 S9 }. j! E7 W3 ?- z    /* Append first four bytes of hash */
! x! Y" {- K" _9 [7 Y; A/ W. ]$ }    bcpy = append(bcpy, hash2[0:4]...)! _& c% U9 X) b+ L7 B
    /* Encode base58 string */( R8 a3 n7 ?% j  X5 B4 N& }
    s = b58encode(bcpy)
* B6 Q, n8 K- f8 l& v    // /* For number of leading 0's in bytes, prepend 1 */5 X% |9 J7 j6 t6 D/ Y9 ]
    // for _, v := range bcpy {
, l" ?% l! F+ ]" V8 D" p    //  if v != 0 {2 H( Q1 D$ i) C$ L+ R5 y
    //      break
* T. T) I4 k" H    //  }" Y- F0 c0 o0 Q9 B
    //  s = "1" + s
/ o& u1 u+ q% G$ @4 H    // }
3 i' s; e2 k- k4 G! U; ^    return s
1 E1 }5 L- p* s7 T( m' h0 G}  F8 @4 H% w# T2 L( h$ |
WIF 是怎么来的?9 r7 P; T( M+ r9 W: D' U% q
WIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:
5 n/ h' G- P3 f! T前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码  B$ @6 A+ _7 o/ m) X4 T
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8