Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

放弃六月们
2330 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。
; B$ j5 [7 y5 m; e) n) [1 n, Y见 Account.swift 类:
  J# |7 w$ K9 ?  T1 ~: Spublic init?() {# T, o( M! J2 u' I9 l$ v5 `
        var pkeyData = Data(count: 32): `; F: n  r0 N: V& L: [8 m
        let result = pkeyData.withUnsafeMutableBytes {
1 M' ^% u$ l4 j" u) B: f            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
8 v6 d' }3 m- j% W( p) d        }: w; D" \, @* Y* D/ R- A
        * i' r8 J9 P$ x+ N. A0 c
        if result != errSecSuccess {- c# D* q2 O7 t/ h3 q0 l0 b- D
            fatalError()
4 q" u) J+ X0 N, L$ V5 l( {        }/ g6 S4 i$ P* ]. ]+ p% ~4 D$ T
          S: w+ l! g( C# R; Q& b+ f
        var error: NSError?
4 t; T: h3 m. j) v/ i        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }" h0 P# @) n& f! l% v
        self.wif = wallet.wif()- f/ w2 A) H7 A1 i& k" E+ u
        self.publicKey = wallet.publicKey()
: J7 p6 s$ {( H4 I  S" l        self.privateKey = pkeyData+ J) D; E3 d  T9 h! Z) ~* _
        self.address = wallet.address()) i$ e. W& e2 [' F$ @; `6 r6 P
        self.hashedSignature = wallet.hashedSignature()
1 ~6 O, F7 o* G) [2 u( f0 t        //default to mainnet& {8 ~: Q8 \* i3 n. {
        self.neoClient = NeoClient.sharedMain$ Y! U& n( A+ _8 i4 s; @# y) P' l
    }
7 V$ [0 Y1 x/ t* s% N它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:/ ~6 l  y+ e4 O5 Z. s) N
/*!$ i, @) C, p+ \& w
     @function SecRandomCopyBytes4 _3 M1 p8 [* O# W3 w1 a
     @abstract Return count random bytes in *bytes, allocated by the caller.$ Z) K( o2 s/ ~" l) Q, l
        It is critical to check the return value for error. [. j6 I0 e, m7 W
     @result Return 0 on success, any other value on failure.
, x- o4 m1 E5 x' {. ~& Y* n5 h) B*/
# j1 d( I' n, {) x* w@available(iOS 2.0, *)1 f- |- P# {; v) V% f
public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32- B! z4 M2 w& \( s
随机生成一个32字节的 Data 数据,即 privatekeyData:' [. }) \% V: v( a% i  P2 U7 \/ i
var pkeyData = Data(count: 32)
) z% M0 t$ {8 z; Z, E) C( ^        let result = pkeyData.withUnsafeMutableBytes {  O% m3 p( j3 `! S( b/ L4 b
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0): B% K) c" M) v9 w/ ]- K2 q
        }/ w  @" F1 k8 a, F
然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:
, N$ o9 t+ y/ `3 c: R6 {5 Bvar error: NSError?
  U/ S1 W% F/ s' g0 Lguard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }3 d+ l' E; g$ i. ]
// Generate a wallet from a private key
6 h/ W  v5 c' ]! E  A5 J2 `- s/ \& c. zfunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
2 N* Z3 g! U1 ?  W    pb := hex2bytes(privateKey)
6 ]+ _2 _' u6 @; J    var priv btckey.PrivateKey3 V# q  Y$ B5 n+ T, F
    err := priv.FromBytes(pb)
% [1 J0 t. {6 R( ~, w3 i2 T    if err != nil {
2 V$ f+ l& `+ |- u8 t8 X        return &Wallet{}, err% Z, Y) `0 n/ Q+ M; `3 s  |
    }5 G0 ^0 p- d1 {! ]
    wallet := &Wallet{  J( q& D) c* w. \3 o7 f
        PublicKey:       priv.PublicKey.ToBytes(),& {& I: Q% |5 N7 D% _$ N# R. m
        PrivateKey:      priv.ToBytes(),% S7 C% [8 o9 u. Z
        Address:         priv.ToNeoAddress(),
/ X- c( ^2 l$ h4 {; ^6 ?; u        WIF:             priv.ToWIFC(),
3 m- v: W+ s' \3 E5 a5 N        HashedSignature: priv.ToNeoSignature(),  Q: d  ?% {$ l% s6 d. u1 Q
    }
  a" s5 X  x. l( x" U) L    return wallet, nil
6 [* W* I. A1 q1 [( w( y}
! z+ W2 ]4 j4 p, ~- C/ ~6 }公钥是怎么来的?, w8 e1 g$ x8 T/ s' W
公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。# S) E- o$ y6 B- E& D
见neowallet.go 和 btckey.go:
9 t7 p8 P9 }$ A' S+ }// Generate a wallet from a private key+ @# v; C' s2 A( `, H2 ^
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {# A- T! |. |5 E' @. |
    pb := hex2bytes(privateKey)
; p- E9 J8 M( z. o' g    var priv btckey.PrivateKey% W2 B9 I2 h* Y5 f
    err := priv.FromBytes(pb)
9 L, d% i. c& D6 N% a    if err != nil {
* g. N, I8 Q3 A& J( H& [2 Q5 f        return &Wallet{}, err
$ L7 R7 j6 U) R. w# b    }# Q  h7 [$ ], W8 F
    wallet := &Wallet{7 h2 @, M0 B8 T% b1 x
        PublicKey:       priv.PublicKey.ToBytes()," z: B; j$ R2 Z4 y* Q( @
        PrivateKey:      priv.ToBytes(),8 Q& c2 p. B4 l3 F) F& Z( b0 U
        Address:         priv.ToNeoAddress(),1 z# f3 j' R/ _# s
        WIF:             priv.ToWIFC(),. o- D9 q/ |! f$ J8 \
        HashedSignature: priv.ToNeoSignature(),. q8 x9 L5 h, Q
    }! u) ~. U" ]: c6 n$ u( i' Z
    return wallet, nil- }5 Y2 b2 e% ?/ g( f* X$ a
}
9 @: X7 ^0 M# |" r/ p1 \+ i( b9 o6 {// derive derives a Bitcoin public key from a Bitcoin private key.2 ^. C# G( J# O: e
func (priv *PrivateKey) derive() (pub *PublicKey) {
0 X. Q0 c. C$ _    /* See Certicom's SEC1 3.2.1, pg.23 */7 V4 H  o: ?- l! T# @7 R
    /* Derive public key from Q = d*G */
, R0 `6 {: \; N    Q := secp256r1.ScalarBaseMult(priv.D)
1 p) k, T6 B) T& |1 `3 O" R    /* Check that Q is on the curve */
! h3 T7 @! {7 |7 D( J5 Q- w) ~& b    if !secp256r1.IsOnCurve(Q) {. X0 T& w  E  G" s% H1 E8 P
        panic("Catastrophic math logic failure in public key derivation.")8 b0 z& e' U0 p% [  r
    }
# v+ e! S' P# r3 e; E4 ^1 ]+ v0 D    priv.X = Q.X
- i, H: r% i0 z, H0 M" L    priv.Y = Q.Y
( x+ U* z7 O) q    return &priv.PublicKey9 x& r7 Q5 d  D' x, r
}: b, w/ p9 Y0 e( N* L
地址脚本是怎么来的?
8 o4 Q6 d1 S* N3 F地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:& o, O% z* J& x. Z2 x) |, B; ?+ {, b
前面是:0x21后面是:0xAC
+ ?# S" H  C3 m( ?; g
$ W7 C+ S& l7 C4 S- E
见btckey.go:
9 P7 A1 j7 G' F+ m  t# o/* Convert the public key to bytes */; y5 }3 k3 A% I  ~* g4 k7 v' @( l4 E
    pub_bytes := pub.ToBytes()! [8 V3 v8 W! y8 X3 U$ F
    pub_bytes = append([]byte{0x21}, pub_bytes...). f) l0 T' b- X' d3 \. b/ ?& r
    pub_bytes = append(pub_bytes, 0xAC)% c4 H% x2 a" ]# w
地址ScriptHash是怎么来的?
( p* F; l9 t  l% S1 {4 X$ w% p- K地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:- \' J. y+ N6 j+ j' Q8 f1 m
见btckey.go:+ Q$ c8 L" D/ H5 e+ b0 R
/* SHA256 Hash */. X$ a1 E5 c: }; Q) P* n( s) n
    sha256_h := sha256.New()
& W) E( {! [6 p, L* q* ~0 L& _+ s    sha256_h.Reset()9 @! l/ E; r4 }0 z& K- J- }$ i" y  c
    sha256_h.Write(pub_bytes)
$ B7 ^) @! _2 Z& C# `    pub_hash_1 := sha256_h.Sum(nil): S+ a9 S  T- A& Q5 ]; \% h3 X
    /* RIPEMD-160 Hash */
# O0 S7 _$ O( b' y  C3 p* y  S$ s  A    ripemd160_h := ripemd160.New()
2 ~* a) k7 `* V    ripemd160_h.Reset()* h, `! u( l9 Y2 ?' k# L' i, J. z  n
    ripemd160_h.Write(pub_hash_1). h2 w8 i# _' m
    pub_hash_2 := ripemd160_h.Sum(nil)
6 O/ I$ d. M+ w; i- s3 Z) m    program_hash := pub_hash_2
; G, n/ D: n, o0 y0 s/ M地址是怎么来的?& h% T6 Y* i3 o9 `) h
地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:
" t# x  B+ F" M% e加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码% y$ p+ b% F3 J3 B1 ]" @
7 I, W3 D. C5 I" w
见 btckey.go 完整的由公钥生成地址的代码:; L" g9 ?* M5 N) F1 F3 R
// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.
* }9 q, B2 e' i7 F- Efunc (pub *PublicKey) ToNeoAddress() (address string) {
. d; N: ^9 K8 u9 O4 E    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */  w' W3 X/ T" C5 E! ]' R6 x/ q. @
    /* Convert the public key to bytes */
3 u# ^' P2 L6 ]  F7 A    pub_bytes := pub.ToBytes()
: h/ t9 v$ ^0 V2 x    pub_bytes = append([]byte{0x21}, pub_bytes...): @. f4 `6 n: p, ~" I( G3 D
    pub_bytes = append(pub_bytes, 0xAC)
4 }* f) n% g4 R3 e" _* A    /* SHA256 Hash */
! @" M1 F8 S$ y2 {9 P2 f" p+ E7 N    sha256_h := sha256.New()
* o" ~* z& K  M* C- m    sha256_h.Reset(), n; ^; j2 ], D
    sha256_h.Write(pub_bytes)3 t% D# s6 G5 H
    pub_hash_1 := sha256_h.Sum(nil)1 J0 L. ~4 j6 L1 I) T
    /* RIPEMD-160 Hash */
! t$ X" A- E" \# t8 u4 H3 j& c    ripemd160_h := ripemd160.New()8 H' c, X! x3 Z8 `5 W
    ripemd160_h.Reset()+ Y3 b9 Y! M4 J# f
    ripemd160_h.Write(pub_hash_1)
# f1 ?* V4 G. z7 a  Q" w6 L- Z) f2 ]    pub_hash_2 := ripemd160_h.Sum(nil)
# U# o1 y- H0 f3 u) Z. G    program_hash := pub_hash_2
# j/ F1 Y1 t% }( H5 V$ O& s# [    //wallet version
- {' h+ T8 s0 w: W1 _6 I    //program_hash = append([]byte{0x17}, program_hash...)
7 }/ g2 _, f, q* U# E% C. C    // doublesha := sha256Bytes(sha256Bytes(program_hash))
$ S8 Z/ m2 I) F7 m    // checksum := doublesha[0:4]
1 @. q# d6 }: S1 L  Z7 O* C    // result := append(program_hash, checksum...)
1 y3 h& u, B( D5 F4 k7 f8 o    /* Convert hash bytes to base58 check encoded sequence */
: e# {& {! N  N, G    address = b58checkencodeNEO(0x17, program_hash)' b3 l( _; O$ l% W4 v& X3 ~2 O
    return address
( Y  c0 ~0 ?8 e' r}
1 J* B8 ~8 L/ h4 U// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.; d1 H( [! q' c2 b- [0 z: t8 y2 u3 q
func b58checkencodeNEO(ver uint8, b []byte) (s string) {
! `" `/ o8 C3 C! [. {2 v    /* Prepend version */( ~1 [0 o/ F$ w1 `; ~2 l
    bcpy := append([]byte{ver}, b...)  o) |. X. \6 G
    /* Create a new SHA256 context */: F+ x4 m9 ~- v9 A4 |. i0 B* u
    sha256_h := sha256.New()0 M8 ^" S6 s6 F7 r+ _: `/ @- C- f
    /* SHA256 Hash #1 */
* R0 A  B$ o& y$ p% m    sha256_h.Reset()9 s3 h& |! p, H6 P6 F& L
    sha256_h.Write(bcpy)
1 U; [! `4 e8 w3 n$ j/ I" Y    hash1 := sha256_h.Sum(nil)' H) ?* C' p) u: {8 u7 n# g
    /* SHA256 Hash #2 */
5 l9 i, E7 ]' q3 c/ Y    sha256_h.Reset()6 d: m/ a" K+ [6 Z/ K
    sha256_h.Write(hash1)
7 x0 [) A9 Q; V' g+ e7 n* f( R/ I    hash2 := sha256_h.Sum(nil)  v' B" A# {/ v' t" |
    /* Append first four bytes of hash */
5 ~7 e0 U: I( r0 E6 L. Q3 u    bcpy = append(bcpy, hash2[0:4]...)
0 k9 I3 j' Y$ U3 }. a1 h    /* Encode base58 string */
( R& G: P6 Q5 D8 @: t    s = b58encode(bcpy)
# D+ Y6 q. |/ h4 X    // /* For number of leading 0's in bytes, prepend 1 */- U8 U3 \. @4 G9 z, h
    // for _, v := range bcpy {
( ]8 O2 U5 m# a$ H8 j# d    //  if v != 0 {
$ x  Z- p; n7 t    //      break
8 W% B5 A; z) Z5 J2 L5 q    //  }0 K0 C- m2 i5 b* n: T
    //  s = "1" + s! U$ u6 I* I$ g- f( Z3 e  P) W; M# Z
    // }* W, ~3 S) f* I, W
    return s9 k1 ]0 p7 K' K1 L  T% L) V
}
: I, ~. j& z7 E* G/ F, VWIF 是怎么来的?+ p( M4 W6 J* ^) J
WIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:4 G# e# {7 U5 ^$ W) q; a
前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码% a: u* M# M7 @' r! n& i
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8