Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

放弃六月们
2387 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。
0 z! f2 J, W% k' N  w见 Account.swift 类:
; x3 P  j! G4 s; U0 opublic init?() {
" @- L9 E7 m$ b6 O2 k8 J2 ^$ Q        var pkeyData = Data(count: 32)& n& A" P9 k4 ]5 P
        let result = pkeyData.withUnsafeMutableBytes {
' w' X3 _- m% u6 I+ M. X* \! i            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)) J: F1 I: D7 f
        }
6 @, g( k- v. B2 h        9 ^" y& {. V' R4 N' P& S4 ^! a
        if result != errSecSuccess {, \0 M# |5 J2 C; [+ n$ g
            fatalError()
, z- K& i8 K1 L+ B        }
4 r" n, q( s" b  C        
, b+ k8 E; o# _' b6 e% U8 ?4 I        var error: NSError?( _7 U: M( M+ e4 P
        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
# h% B" C0 v# W! X" S9 H        self.wif = wallet.wif()# K) H: k: U  {8 f) a& S
        self.publicKey = wallet.publicKey()
* P5 o) A7 w3 P7 }+ s+ D6 m        self.privateKey = pkeyData
5 A' H1 o9 `" r+ e8 H( s        self.address = wallet.address(); r/ d" V) |# Z
        self.hashedSignature = wallet.hashedSignature()
' B/ h6 ^( D  _- u# C; U% {        //default to mainnet
( \- }! V0 N8 E2 G9 r7 t        self.neoClient = NeoClient.sharedMain1 u3 C3 W/ d+ m: @  g
    }2 Y" k7 l# c( c) c
它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:
! s/ \; N( c6 S6 o1 b/*!/ `) S& n  l/ I. Z/ @; y: v
     @function SecRandomCopyBytes
9 E, t' N3 [* S- U( w  y1 w     @abstract Return count random bytes in *bytes, allocated by the caller." x& Z4 z7 Z; L" ]' d$ J" L
        It is critical to check the return value for error+ `& ]: i" D, @* O6 f
     @result Return 0 on success, any other value on failure.8 ?' j; K9 O. a
*/
  J: V- `6 J5 x  S; j@available(iOS 2.0, *)7 k0 Z1 w" P0 ~& V" z4 [: f
public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32
$ x% B, B# f+ y& t随机生成一个32字节的 Data 数据,即 privatekeyData:7 K- t. Q" h6 p) M" \. |! E, H4 v$ q
var pkeyData = Data(count: 32); g2 m: T- D+ G& @6 a) R3 Y
        let result = pkeyData.withUnsafeMutableBytes {
! u( S( G5 H0 w; b            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
) g3 K8 |0 `5 o6 G" r% }: k6 Q        }
5 U% P8 L1 [2 F/ r& q然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:0 F4 x7 B0 i: A1 }) E5 x
var error: NSError?2 ]! U( h9 j9 @. {$ d/ V
guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }/ ]: H+ g' O/ z7 i( ~/ r7 R& Z
// Generate a wallet from a private key, R  U! w; B4 n1 w; u4 R" l
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
2 c* X2 z, X- F# ]/ `    pb := hex2bytes(privateKey)
' |1 P) c( z8 }' `, Z; c! v    var priv btckey.PrivateKey
1 f. C" Z4 e3 m" ]    err := priv.FromBytes(pb)
: d' ]( l4 H1 G    if err != nil {
/ u- Q  g8 P  ^- s3 \  Z5 U        return &Wallet{}, err, v# ^, J" z( I! H8 y4 w* k6 @
    }" c+ R% a  v3 W. b0 G
    wallet := &Wallet{" M/ i' w# e3 N+ h8 M
        PublicKey:       priv.PublicKey.ToBytes(),
  a, G; S- @. f, p% K% X  e        PrivateKey:      priv.ToBytes(),* q: ]* F- L$ \
        Address:         priv.ToNeoAddress(),
! a4 Q. V5 `; v" y        WIF:             priv.ToWIFC(),
4 S9 N) `( ^3 A        HashedSignature: priv.ToNeoSignature(),: Y6 s) _9 k" v" a3 q! s
    }$ p8 [0 J5 K& ^) Q; J3 E) S
    return wallet, nil
& e$ A3 r; E: d. w# y}4 Y6 Z1 \$ n8 a
公钥是怎么来的?
2 O7 P  p$ Q  u, p. |! y$ Q8 v公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。
% E9 S4 t1 ^  q8 K见neowallet.go 和 btckey.go:! i; |: L( K' T) |5 n6 L
// Generate a wallet from a private key
2 i6 t$ w9 W* X( y, ufunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
% @5 G; u/ Z: s$ f6 M. k2 T    pb := hex2bytes(privateKey)3 m) }' `7 v1 C  Z  I
    var priv btckey.PrivateKey
" M1 G  W! l' q* N& n' e2 e2 }    err := priv.FromBytes(pb)
% ]$ S! \. `4 n) n! t    if err != nil {
" |) ]2 p7 ^8 p1 A2 c1 o3 {& ?3 z        return &Wallet{}, err' G; y: H( q# @/ w
    }
$ o! @3 u, w# Y! T    wallet := &Wallet{$ Y- W- v3 P4 }/ k/ t3 E" y$ n# b
        PublicKey:       priv.PublicKey.ToBytes(),; z; g2 C# Z2 }0 ^+ |" l% o
        PrivateKey:      priv.ToBytes(),
" B9 P# b2 d6 B% R$ u6 t8 J        Address:         priv.ToNeoAddress(),
' Q, W9 c, i) B" e/ H2 w: @' @        WIF:             priv.ToWIFC(),
  D7 ^: M6 V% l( ]% q0 |        HashedSignature: priv.ToNeoSignature(),
* Y; @" [5 t/ k, x( A( R: i    }
: D) C. R6 t- }6 b2 l  V. Y; C( r    return wallet, nil6 {) l3 |( m- n! D; w. m
}
+ U/ F; l/ W1 v0 V// derive derives a Bitcoin public key from a Bitcoin private key.
/ c$ Q% ?# P: T1 w1 _4 u9 Z6 Gfunc (priv *PrivateKey) derive() (pub *PublicKey) {0 o0 F* L) y5 b. J
    /* See Certicom's SEC1 3.2.1, pg.23 */
1 C' Z8 W# z, ~3 q) s    /* Derive public key from Q = d*G */
0 g" n5 e0 {; Q) p+ ~    Q := secp256r1.ScalarBaseMult(priv.D)! E7 s* w! B" G  E/ o3 Y
    /* Check that Q is on the curve */4 W& G; j6 z2 K" A
    if !secp256r1.IsOnCurve(Q) {
4 j: Y, G' C! C: i8 _        panic("Catastrophic math logic failure in public key derivation.")
  m$ T# }6 q. Q+ }    }
8 d3 F; n0 n8 |% h    priv.X = Q.X2 L/ i: w2 A* K* G, X! N
    priv.Y = Q.Y
0 F+ V' `2 N5 `% w8 _7 e/ @& e    return &priv.PublicKey1 H. ]8 D4 U! W8 K
}
0 f  ]0 Z8 T! B8 J3 x# Q( y* Z地址脚本是怎么来的?, |8 E/ i2 C9 `3 c3 \7 h' N
地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:
3 K) n) c3 D8 `5 u  D# Q前面是:0x21后面是:0xAC
! T- E) u9 M" o, j8 U$ D+ S
9 i$ O! _+ v$ W$ P2 z2 T
见btckey.go:# P8 Y3 r2 b5 J5 z5 D/ W. W
/* Convert the public key to bytes */1 Z! [$ r' ~* p( I% o" b/ Z
    pub_bytes := pub.ToBytes()( @; ]2 `( E6 _4 C
    pub_bytes = append([]byte{0x21}, pub_bytes...)
8 w0 o$ w( v" J9 s    pub_bytes = append(pub_bytes, 0xAC)
* Y; q; ^! ~/ h, j, m地址ScriptHash是怎么来的?) S  v+ |6 G. F3 X. `
地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:
: \' U% d: |2 G/ d  d- F" k见btckey.go:
. r: F5 J! G6 Z( x4 d' I! n+ V3 [: V/* SHA256 Hash */: a- ^% T0 \7 e, g8 G! g7 a% ]2 H# X  D) L
    sha256_h := sha256.New()' B" z, B" e+ }3 t! R5 Z
    sha256_h.Reset()" k- \- W5 z4 q2 a. d# Z9 |
    sha256_h.Write(pub_bytes)" W( P/ c9 l5 C- U3 i
    pub_hash_1 := sha256_h.Sum(nil)
8 C$ H) x% y3 [$ M' Q$ a    /* RIPEMD-160 Hash */* W& r+ T: E: \
    ripemd160_h := ripemd160.New(); A8 \2 O- m3 x6 W$ i" y
    ripemd160_h.Reset()
: w+ l8 l  o4 Q: w9 N0 I    ripemd160_h.Write(pub_hash_1)0 ^8 }9 O2 f9 Y# Y) ~; l
    pub_hash_2 := ripemd160_h.Sum(nil)
3 q; u% U- M4 e( Q# L    program_hash := pub_hash_2
  W7 E5 P9 u( [, J地址是怎么来的?4 C; d& R/ S1 Z1 n: |! y! o
地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:. ?8 J) W2 H  k+ O
加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码5 u  y6 ?4 U  R  S0 `8 G
" W8 M9 i0 v  ^2 G6 d
见 btckey.go 完整的由公钥生成地址的代码:
9 D6 k* `! z1 W2 ^  h// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.
: g* R* G. ~. `3 K- Y& Y8 efunc (pub *PublicKey) ToNeoAddress() (address string) {
9 l; g9 A, ]) E( K2 l" m) v( T    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */; G: j, Z- m; Q( ]6 r1 ^) y
    /* Convert the public key to bytes */" y: |3 ^6 W+ O
    pub_bytes := pub.ToBytes()
' w- y  ?) c; e- G) i6 Z    pub_bytes = append([]byte{0x21}, pub_bytes...)0 S* s& \3 P  F* S) Q
    pub_bytes = append(pub_bytes, 0xAC)2 b$ Y7 M& ]1 Y5 a
    /* SHA256 Hash */
/ p7 T6 M, x( y    sha256_h := sha256.New()
/ ?4 t" P3 B, @, D1 \5 i    sha256_h.Reset()1 G9 _2 K  F% T% F
    sha256_h.Write(pub_bytes)
3 ]5 y8 u$ k5 |    pub_hash_1 := sha256_h.Sum(nil)
% D$ Z: c1 G( Y2 ?  c7 ?    /* RIPEMD-160 Hash */7 Z# ?8 E$ s8 X1 ^3 L. u# x: C
    ripemd160_h := ripemd160.New(). W$ x# X  A* h3 a( S  F7 q
    ripemd160_h.Reset()
# S& Z3 z- i+ s% v9 x4 T    ripemd160_h.Write(pub_hash_1)
% ?  }  u. x: k1 |4 F5 [    pub_hash_2 := ripemd160_h.Sum(nil)
! T1 C% d; w5 O+ ^    program_hash := pub_hash_2
; s# m' I2 q! O+ Q+ k" o$ f1 J    //wallet version5 U2 i9 U3 H  r
    //program_hash = append([]byte{0x17}, program_hash...)8 L+ a$ L$ F3 r
    // doublesha := sha256Bytes(sha256Bytes(program_hash))/ I/ n$ ?$ v# e( i
    // checksum := doublesha[0:4]8 s) P" ?# q2 A, j/ T9 X! ~
    // result := append(program_hash, checksum...): m, t3 `  `2 a& n! G
    /* Convert hash bytes to base58 check encoded sequence */9 y. f) p- x$ B8 Q2 r6 @) Y
    address = b58checkencodeNEO(0x17, program_hash)
  ?0 R' o# @9 l, L    return address
+ c! s0 v; o9 E8 K}' w6 Y; k1 ~8 w6 o/ }0 V
// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.
7 M. n& E6 D7 e/ \' C# C) Qfunc b58checkencodeNEO(ver uint8, b []byte) (s string) {2 X/ h. [# s' v
    /* Prepend version */
, b2 ]$ v- g8 a  O1 m+ c! t& ^    bcpy := append([]byte{ver}, b...)
6 i; w( g. g3 ?    /* Create a new SHA256 context */
/ Q* x/ e: a/ v# m: p    sha256_h := sha256.New()# c/ u3 Q1 l& }( ]; V
    /* SHA256 Hash #1 */
; E$ C+ v9 n1 y, c. u, }8 O4 o    sha256_h.Reset()
  Z- H) Y; ^! m2 X( ?3 B: V    sha256_h.Write(bcpy)
8 w. f* o& H. t2 I    hash1 := sha256_h.Sum(nil)
0 Y1 ^2 K: Y) ^) A    /* SHA256 Hash #2 */6 k/ G9 i9 h6 \% W
    sha256_h.Reset()% x9 G; q4 O  f& j
    sha256_h.Write(hash1)- |+ T7 [- G2 r/ G4 u
    hash2 := sha256_h.Sum(nil)) \3 r' z+ _% I1 M5 E7 x
    /* Append first four bytes of hash */& [( q8 t- ]6 ~  ^# a7 t
    bcpy = append(bcpy, hash2[0:4]...)
" l7 X4 E- c& u8 S$ ^0 p) r    /* Encode base58 string */
* E* m8 A. x3 F' q4 l    s = b58encode(bcpy)" O. t4 K( w4 \/ a
    // /* For number of leading 0's in bytes, prepend 1 */
5 y. ~1 x. K& K( w/ p$ O    // for _, v := range bcpy {
; {' p0 p0 Y9 Y( @6 V' b* t6 |    //  if v != 0 {* W, x1 H8 l9 _8 R4 z% b$ x4 C8 d
    //      break
6 F( |$ g  w  B4 \$ z    //  }
; H' f& p+ K/ c) H5 A0 G) N! o! x    //  s = "1" + s
% t! b/ ?1 A5 \. E" n    // }  m* a4 z0 \' U& ^- T  C4 t: H. T
    return s- A6 D# |# C' u3 d+ m1 h) W6 s  a
}, N5 [3 R; o1 K- B8 S+ T/ ]) x  ?
WIF 是怎么来的?
* O% H8 M$ k4 @7 M% A5 zWIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:" x0 u8 V# Z/ K# @
前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码4 Z0 ^. i; ^7 C0 ?
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8