Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

放弃六月们
2327 0 0
私钥是怎么来的?私钥是一个32字节的随机数,这个数的范围是介于 1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141 之间。. V4 X( n' U7 @! d: P+ H
见 Account.swift 类:( Z5 K5 ^8 X3 [4 l
public init?() {
8 g+ l0 d; N( }. T        var pkeyData = Data(count: 32)
! \  o& Q9 ^4 ~        let result = pkeyData.withUnsafeMutableBytes {) S$ @- ?8 ?3 ?3 J
            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
+ i( D0 t4 [7 `( C9 q; C3 h        }* R3 n0 i  d" A
        
( v9 G. J* n* X$ C5 S+ y        if result != errSecSuccess {
7 d6 g4 {  b2 H1 Y. q            fatalError()7 b4 w: u' \, H- V! d
        }7 M, {& E8 T2 r% h+ t- j
        1 V6 f& z: ]% ^$ G
        var error: NSError?/ m8 h' K' y" T
        guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }5 N+ |- Q) g; L3 ~5 J' i4 }
        self.wif = wallet.wif()0 c; y. e1 c; L9 G+ ~
        self.publicKey = wallet.publicKey()  S4 {' e$ H' i: t$ p' f
        self.privateKey = pkeyData
7 _0 ^. t" p4 U4 A7 S( [        self.address = wallet.address()
0 c( v! Q; g, x+ C' ^* _. k        self.hashedSignature = wallet.hashedSignature()
& r; s! h$ y$ v6 {# u9 H        //default to mainnet+ M2 e  n2 w# l. x
        self.neoClient = NeoClient.sharedMain
0 |0 H* a7 G3 C6 t5 A- Q2 D' A    }$ o* u- ~4 u5 x+ l$ [% B
它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:, o2 X9 k, ~$ V4 B
/*!
  Y# \0 A" [# W! C' [     @function SecRandomCopyBytes
  |2 i$ v  e, P3 ~# g1 J     @abstract Return count random bytes in *bytes, allocated by the caller.. A8 l8 C$ y! H! z' w
        It is critical to check the return value for error& {% P( m8 f8 L6 s, g5 X
     @result Return 0 on success, any other value on failure.
  N  A4 u' X8 N  Q' ]. w5 J*/* y3 |& w6 C$ V( j+ {
@available(iOS 2.0, *)$ j) L, q' }7 K/ @' q% n7 I3 S
public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32+ m, ?+ X& A& s9 j; t4 `" k
随机生成一个32字节的 Data 数据,即 privatekeyData:
) S' q- O  b5 z; j3 ?6 Wvar pkeyData = Data(count: 32)$ C* Y& C8 ]; Y; g: y2 W7 O
        let result = pkeyData.withUnsafeMutableBytes {
" H! }; ]% o/ x1 v% \' T' r4 h            SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0). l5 f. A6 Y% n/ O
        }8 I. X' m9 N7 L$ ~
然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:- ~2 x" Y* ?2 w7 Q
var error: NSError?* f/ L  r0 O2 Z6 u, F
guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }( }6 k- W! z" G
// Generate a wallet from a private key
5 ]/ e" l8 K* P3 ~func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {# B) U5 Z4 M; `. G! ^
    pb := hex2bytes(privateKey): R0 z3 b" ~6 t) M9 z$ H' h) v
    var priv btckey.PrivateKey7 \  K* ^, ?* ^/ g0 a" [( M
    err := priv.FromBytes(pb)! i$ w2 k% Z2 I$ Q
    if err != nil {- W# W& y5 C0 ^4 D5 a
        return &Wallet{}, err1 D: L! X& d; F; f
    }4 ~% x1 d, o& k+ c  }
    wallet := &Wallet{
$ n  a0 T& }3 u8 T        PublicKey:       priv.PublicKey.ToBytes(),
. i( Z3 S- ~" s4 Z( w6 p+ u+ ^        PrivateKey:      priv.ToBytes(),
8 s# ~4 U  t5 F' S        Address:         priv.ToNeoAddress(),
7 B, w" U! j% k" r* R4 U4 Y" \0 y- n# ^        WIF:             priv.ToWIFC(),% O' ~0 q# e% ]8 }
        HashedSignature: priv.ToNeoSignature(),
0 v9 k& w+ R* S* Y4 z    }
  f8 Z" J+ n$ U0 V6 d2 `" B) B    return wallet, nil
) Y1 b9 k4 ~+ Z, W. a. O}
7 R$ f! `) X$ D9 F公钥是怎么来的?  B+ d% M/ t& @/ w& ^& V# C$ z
公钥是用私钥通过椭圆曲线算法得到的,但是无法从公钥算出私钥。6 U5 I; N# U, u/ V
见neowallet.go 和 btckey.go:
6 F6 G& T. n6 u2 ]// Generate a wallet from a private key6 U9 g4 K2 Y* U
func GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
2 m7 v! N  i$ z( ^    pb := hex2bytes(privateKey)( R8 `: U" u& E8 F& \
    var priv btckey.PrivateKey: Y* o1 E/ t. }; W# ^7 n
    err := priv.FromBytes(pb)9 J% r8 J9 a( U% m" f* w1 G
    if err != nil {
' M. e! |+ [- W  G( y5 w9 j# {/ |) ^, h        return &Wallet{}, err
) Y' o- K4 P" V, ?, ~) b% |6 r3 x    }
' ?0 Z# O6 V4 o7 Y' P$ q    wallet := &Wallet{' u  `9 O3 \) k6 u
        PublicKey:       priv.PublicKey.ToBytes(),3 {- D& x0 j) l. z3 x& ^) j
        PrivateKey:      priv.ToBytes(),
8 z+ |1 Q- c' i" B' H  H        Address:         priv.ToNeoAddress(),; L( E; ]8 L- P3 Z* f* {$ g
        WIF:             priv.ToWIFC(),) J, B1 C* t; k. c1 i; X
        HashedSignature: priv.ToNeoSignature(),
/ @6 F3 L5 S# ?    }4 `# f' x( j3 J4 P/ T5 o5 d0 ]) w
    return wallet, nil! }8 t9 u' K! D' q0 X& G
}
( H- W0 D, V: a9 B( G0 d2 J// derive derives a Bitcoin public key from a Bitcoin private key.
% M& c$ i/ {8 q* R3 J! k' i3 gfunc (priv *PrivateKey) derive() (pub *PublicKey) {+ O7 m. {5 y9 F; W; u9 \; E3 d+ K
    /* See Certicom's SEC1 3.2.1, pg.23 */3 ~! ]! g; |$ y5 ]6 r* w! @
    /* Derive public key from Q = d*G */
8 Q) v4 G) h8 d9 J' f. G    Q := secp256r1.ScalarBaseMult(priv.D)9 ^/ L2 N5 u, l. {
    /* Check that Q is on the curve */0 V: v5 n6 x! o- j' g
    if !secp256r1.IsOnCurve(Q) {
  B4 f9 R# S1 M$ |        panic("Catastrophic math logic failure in public key derivation.")
2 w# ]6 e2 ?7 h2 J5 C    }
( [( W) K# z/ I' j! p$ a    priv.X = Q.X
, A5 Q) Y/ x  O5 b: p5 b9 ^: M    priv.Y = Q.Y7 j& \! W+ E3 P
    return &priv.PublicKey3 W+ H: _3 Q: g9 x9 _
}- k7 ~5 V# |$ F* q2 Z3 W5 X
地址脚本是怎么来的?
+ ]7 s1 z5 G4 p( k地址脚本是由公钥前后各加了一个字节得到的,这两个字节是固定的:' u7 G4 W5 [  c6 I4 h9 Z( y
前面是:0x21后面是:0xAC
# ]. K5 L9 P1 l6 P8 m! Q! ~+ e

: Y2 r0 D- {6 C# a7 t见btckey.go:
6 c( |4 {) l& N# h  L  _/* Convert the public key to bytes */
" x6 B( b! ~8 s# Z1 @    pub_bytes := pub.ToBytes()
$ Z  U& [+ z3 Q, `    pub_bytes = append([]byte{0x21}, pub_bytes...)
2 c3 T5 v' l* j    pub_bytes = append(pub_bytes, 0xAC)! ~3 ?6 G# b" m( y
地址ScriptHash是怎么来的?8 C2 {! u# D6 r# {2 \
地址ScriptHash就是地址脚本取了个Hash,一次 sha256,一次ripemd160:
8 t; m$ G% x% i1 }见btckey.go:
7 t8 _9 [  p, I1 ^/* SHA256 Hash */
1 V# k1 P' b# Q( G( J2 t    sha256_h := sha256.New()
5 ^0 K$ U7 \0 R! {/ N* F    sha256_h.Reset()7 p1 y7 E; A* r
    sha256_h.Write(pub_bytes)
2 T: \1 t+ A7 Z* @    pub_hash_1 := sha256_h.Sum(nil)
1 Y. B$ V3 C+ D& Q    /* RIPEMD-160 Hash */) P9 u# w) H- A" d8 W9 ]
    ripemd160_h := ripemd160.New()
; G& A4 m  w0 W  r# x4 Y0 ~* U    ripemd160_h.Reset()- \, x* q) I8 O
    ripemd160_h.Write(pub_hash_1)5 h7 X6 n3 c8 x
    pub_hash_2 := ripemd160_h.Sum(nil); M. e' e# J, F& Q# K
    program_hash := pub_hash_25 E0 V) b. Q* y' [% r4 ^
地址是怎么来的?
, ~, d& S* y# l地址是由地址ScriptHash加了盐,加了验证功能,然后 Base58 编码得到的:& _; w- R3 L0 ~' k( H* _( X: I
加盐:前面加了一个字节 0x17加验证功能:把加盐后的字节做了一个 hash,两次 sha256,取前四个字节编码:Base58 编码
. y. J8 r: Z" ^6 P/ b
: }/ v1 e+ y' ?# I! k4 K9 Q- f
见 btckey.go 完整的由公钥生成地址的代码:" M( n; \! g3 N* f$ s2 ^2 d
// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.
  W5 |2 ^) \) J$ |: Hfunc (pub *PublicKey) ToNeoAddress() (address string) {
/ u- Z- M4 Z3 {5 K* M  I( o    /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */
6 G3 Z) |  z0 ~: @5 f    /* Convert the public key to bytes */$ M0 X0 I+ b, Y% Y' ~2 [
    pub_bytes := pub.ToBytes()- c' t& s6 o: N% q5 R- B8 l
    pub_bytes = append([]byte{0x21}, pub_bytes...)1 V0 c+ N% Q) c: b' w% Q
    pub_bytes = append(pub_bytes, 0xAC)7 }1 {& j1 l; r: g6 P
    /* SHA256 Hash */2 L* l' S0 l- g9 N% j0 `9 k+ P
    sha256_h := sha256.New()" U$ w0 _. S( S9 |1 F
    sha256_h.Reset()
- r7 `+ b# V$ ~7 M$ `5 C* l# p7 n7 x    sha256_h.Write(pub_bytes)
. j8 w5 v. s2 }/ O+ r- N9 n    pub_hash_1 := sha256_h.Sum(nil)  u2 r: ~  r  b
    /* RIPEMD-160 Hash */3 n8 j% Z: V& B. J5 |( k* p" T
    ripemd160_h := ripemd160.New()' D9 y, V# ]: _4 |
    ripemd160_h.Reset(). k3 [+ s/ r# V1 r$ g
    ripemd160_h.Write(pub_hash_1)
; u$ F$ T3 s$ x, I. s    pub_hash_2 := ripemd160_h.Sum(nil)! ]" c" A/ h! N
    program_hash := pub_hash_2
. P! O# o$ A8 ^/ C    //wallet version( a: @6 m2 [+ X+ X" G- E1 ~% T
    //program_hash = append([]byte{0x17}, program_hash...)
% k; b: d* `8 c( t    // doublesha := sha256Bytes(sha256Bytes(program_hash))/ B- C( S& V# }
    // checksum := doublesha[0:4]# P1 b6 l' F  U; ]
    // result := append(program_hash, checksum...)$ c; [( ~) N1 `. W( @5 L
    /* Convert hash bytes to base58 check encoded sequence */* X) j1 P8 J3 W0 w6 s+ S7 @
    address = b58checkencodeNEO(0x17, program_hash)
: e8 J* A/ U1 W$ a* {    return address
, i0 U1 M1 \1 L/ A8 O}( W! X( M2 \! b  `* m+ n! n
// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.& o6 V7 U, L+ A) m. K* r- K
func b58checkencodeNEO(ver uint8, b []byte) (s string) {
6 R7 h" K. i; ]8 c$ O  C) v    /* Prepend version */
$ p& _5 J# {$ H- z) s  f' {' G# d) i    bcpy := append([]byte{ver}, b...)$ A% p, H* `( t' Y% K% ]5 G
    /* Create a new SHA256 context */
" H$ [4 A8 s( S* v# K- Z9 M    sha256_h := sha256.New()* [3 d0 J; O6 `3 L8 }- R
    /* SHA256 Hash #1 */& Y1 X. d0 e* U" g" Q; _
    sha256_h.Reset()" |  ~( l& e7 A! e. `  G
    sha256_h.Write(bcpy)
5 g: ~' Z* H# v5 O7 Q    hash1 := sha256_h.Sum(nil)0 ?( _# l6 e8 s, c2 c, A6 y
    /* SHA256 Hash #2 */2 ]$ p* ?; _9 t+ c+ ~
    sha256_h.Reset(). u! [3 w9 Q; q
    sha256_h.Write(hash1): O  }: }* q2 [0 ^% U
    hash2 := sha256_h.Sum(nil)+ _7 h* U8 g) D0 s$ H8 D- {
    /* Append first four bytes of hash */; ]7 m8 r, Q% Q6 p+ j( O! k
    bcpy = append(bcpy, hash2[0:4]...)
! v* G" Y. L" G- B    /* Encode base58 string */& U7 R. J( A+ L' w( x, A  I* B
    s = b58encode(bcpy)
4 t. N' V8 W% e, t( S5 ]( P' M$ S    // /* For number of leading 0's in bytes, prepend 1 */3 G. V7 i" }$ z4 H' |) K6 Y- P  a" f
    // for _, v := range bcpy {
. u' m* S6 {# v! q' d" {7 v; J) F" Q    //  if v != 0 {- z9 [  m9 X; ^$ W8 |
    //      break/ H' b6 @6 G1 Y; t  `
    //  }3 E, d; [- u& }, q; `
    //  s = "1" + s
# \! {& @. ~8 @; w$ q/ v7 i7 S    // }
& V9 D& p+ h& j2 q+ N- Q    return s
9 o# D9 k2 i2 U, [$ p, h% d}3 e4 a7 S  J/ W" j4 M6 ]
WIF 是怎么来的?5 O, i. B1 h0 J5 a9 R' i% ^1 _# Y
WIF(Wallet Import Format)是由私钥在前面加了一个版本号字节 0x80,在后面加了一个压缩标志的字节 0x01,然后对这34个字节进行哈希,取哈希值的前4个字节作为校验码加在最后面,最后经过 Base58 编码得到:
* Z" {3 B# ^8 F& l7 c前面加版本字节:0x80后面加压缩标志字节:0x01对这34个字节进行哈希:取哈希值的前4个字节加在最后面编码:Base58 编码6 H# U  b5 Z) x6 N. Y5 D/ c
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

放弃六月们 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    8