首页 > IT职业 > IT图书 > NEO 之从私钥到地址
学习 NEO 钱包的 O3 项目 ,其中有用到 NeoSwift 库,记录一下。
public init?() { var pkeyData = Data(count: 32) let result = pkeyData.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
}
if result != errSecSuccess { fatalError()
}
var error: NSError? guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil } self.wif = wallet.wif() self.publicKey = wallet.publicKey() self.privateKey = pkeyData self.address = wallet.address() self.hashedSignature = wallet.hashedSignature() //default to mainnet
self.neoClient = NeoClient.sharedMain
}
它是通过 Security.framework 库里的 SecRandomCopyBytes 方法,生成一组密码安全的随机字节:
/*! @function SecRandomCopyBytes @abstract Return count random bytes in *bytes, allocated by the caller. It is critical to check the return value for error @result Return 0 on success, any other value on failure. */@available(iOS 2.0, *)public func SecRandomCopyBytes(_ rnd: SecRandomRef?, _ count: Int, _ bytes: UnsafeMutableRawPointer) -> Int32
随机生成一个32字节的 Data 数据,即 privatekeyData:
var pkeyData = Data(count: 32) let result = pkeyData.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, pkeyData.count, $0)
}
然后根据私钥(用 privatekeyData 的 HexString 作为参数)生成一个钱包,见 neo-utils:
var error: NSError?guard let wallet = NeoutilsGeneratePublicKeyFromPrivateKey(pkeyData.fullHexString, &error) else { return nil }
// Generate a wallet from a private keyfunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
pb := hex2bytes(privateKey) var priv btckey.PrivateKey
err := priv.FromBytes(pb) if err != nil { return &Wallet{}, err
}
wallet := &Wallet{ PublicKey: priv.PublicKey.ToBytes(), PrivateKey: priv.ToBytes(), Address: priv.ToNeoAddress(), WIF: priv.ToWIFC(), HashedSignature: priv.ToNeoSignature(),
} return wallet, nil}
// Generate a wallet from a private keyfunc GenerateFromPrivateKey(privateKey string) (*Wallet, error) {
pb := hex2bytes(privateKey) var priv btckey.PrivateKey
err := priv.FromBytes(pb) if err != nil { return &Wallet{}, err
}
wallet := &Wallet{ PublicKey: priv.PublicKey.ToBytes(), PrivateKey: priv.ToBytes(), Address: priv.ToNeoAddress(), WIF: priv.ToWIFC(), HashedSignature: priv.ToNeoSignature(),
} return wallet, nil}
// derive derives a Bitcoin public key from a Bitcoin private key.func (priv *PrivateKey) derive() (pub *PublicKey) { /* See Certicom's SEC1 3.2.1, pg.23 */
/* Derive public key from Q = d*G */
Q := secp256r1.ScalarBaseMult(priv.D) /* Check that Q is on the curve */
if !secp256r1.IsOnCurve(Q) {
panic("Catastrophic math logic failure in public key derivation.")
}
priv.X = Q.X
priv.Y = Q.Y
return &priv.PublicKey}
/* Convert the public key to bytes */
pub_bytes := pub.ToBytes()
pub_bytes = append([]byte{0x21}, pub_bytes...)
pub_bytes = append(pub_bytes, 0xAC)
/* SHA256 Hash */ sha256_h := sha256.New() sha256_h.Reset() sha256_h.Write(pub_bytes) pub_hash_1 := sha256_h.Sum(nil) /* RIPEMD-160 Hash */ ripemd160_h := ripemd160.New() ripemd160_h.Reset() ripemd160_h.Write(pub_hash_1) pub_hash_2 := ripemd160_h.Sum(nil) program_hash := pub_hash_2
// ToAddress converts a Bitcoin public key to a compressed Bitcoin address string.func (pub *PublicKey) ToNeoAddress() (address string) { /* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */
/* Convert the public key to bytes */
pub_bytes := pub.ToBytes()
pub_bytes = append([]byte{0x21}, pub_bytes...)
pub_bytes = append(pub_bytes, 0xAC) /* SHA256 Hash */
sha256_h := sha256.New()
sha256_h.Reset()
sha256_h.Write(pub_bytes)
pub_hash_1 := sha256_h.Sum(nil) /* RIPEMD-160 Hash */
ripemd160_h := ripemd160.New()
ripemd160_h.Reset()
ripemd160_h.Write(pub_hash_1)
pub_hash_2 := ripemd160_h.Sum(nil)
program_hash := pub_hash_2 //wallet version
//program_hash = append([]byte{0x17}, program_hash...)
// doublesha := sha256Bytes(sha256Bytes(program_hash))
// checksum := doublesha[0:4]
// result := append(program_hash, checksum...)
/* Convert hash bytes to base58 check encoded sequence */
address = b58checkencodeNEO(0x17, program_hash) return address
}
// b58checkencode encodes version ver and byte slice b into a base-58 check encoded string.func b58checkencodeNEO(ver uint8, b []byte) (s string) { /* Prepend version */
bcpy := append([]byte{ver}, b...) /* Create a new SHA256 context */
sha256_h := sha256.New() /* SHA256 Hash #1 */
sha256_h.Reset()
sha256_h.Write(bcpy)
hash1 := sha256_h.Sum(nil) /* SHA256 Hash #2 */
sha256_h.Reset()
sha256_h.Write(hash1)
hash2 := sha256_h.Sum(nil) /* Append first four bytes of hash */
bcpy = append(bcpy, hash2[0:4]...) /* Encode base58 string */
s = b58encode(bcpy) // /* For number of leading 0's in bytes, prepend 1 */
// for _, v := range bcpy {
// if v != 0 {
// break
// }
// s = "1" + s
// }
return s
}
https://github.com/CityOfZion/neo-swift/blob/master/NeoSwift/Account.swift
https://developer.apple.com/documentation/security/1399291-secrandomcopybytes
https://github.com/apisit/neo-wallet-address-go/blob/master/neowallet.go
https://github.com/O3Labs/neo-utils/blob/master/neoutils/neowallet.go
https://github.com/apisit/btckeygenie/blob/master/btckey/btckey.go
作者:宅小馒
原文链接
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1627/viewspace-2808759/ ,如需转载,请注明出处,否则将追究法律责任。