4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-19 05:35:48 +00:00
qortal-ui/crypto/api/bitcoin/AltcoinHDWallet.js

846 lines
21 KiB
JavaScript
Raw Normal View History

import Base58 from '../deps/Base58'
import { Sha256, Sha512 } from 'asmcrypto.js'
import jsSHA from 'jssha'
import RIPEMD160 from '../deps/ripemd160'
import utils from '../deps/utils'
import { BigInteger, EllipticCurve } from './ecbn'
2021-12-25 14:39:47 +01:00
export default class AltcoinHDWallet {
constructor(addressParams) {
2021-12-25 14:39:47 +01:00
/**
* Seed - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.seed = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Version Bytes - 4 byte
*/
2021-12-25 14:39:47 +01:00
this.versionBytes = addressParams
2021-12-25 14:39:47 +01:00
/**
* Depth - 1 byte
*/
2021-12-25 14:39:47 +01:00
this.depth = 0
2021-12-25 14:39:47 +01:00
/**
* Parent Fingerprint - 4 bytes
*/
2021-12-25 14:39:47 +01:00
this.parentFingerprint = '0x00000000' // master key
2021-12-25 14:39:47 +01:00
/**
* Child Index - 4 bytes
*/
2021-12-25 14:39:47 +01:00
this.childIndex = '0x00000000' // master key
2021-12-25 14:39:47 +01:00
/**
* Chain Code - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.chainCode = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Key Data - 33 bytes
*/
2021-12-25 14:39:47 +01:00
this.keyData = new Uint8Array(33)
2021-12-25 14:39:47 +01:00
/**
* Seed Hash - 64 bytes
*/
2021-12-25 14:39:47 +01:00
this.seedHash = new Uint8Array(64)
2021-12-25 14:39:47 +01:00
/**
* Private Key - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.privateKey = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Public Key - 33 bytes (compressed)
*/
2021-12-25 14:39:47 +01:00
this.publicKey = new Uint8Array(33)
2021-12-25 14:39:47 +01:00
/**
* Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
2021-12-25 14:39:47 +01:00
this.publicKeyHash = new Uint8Array(20)
2021-12-25 14:39:47 +01:00
/**
* Master Private Key (Base58 encoded)
*/
2021-12-25 14:39:47 +01:00
this.masterPrivateKey = ''
2021-12-25 14:39:47 +01:00
/**
* Master Public Key (Base58 encoded)
*/
2021-12-25 14:39:47 +01:00
this.masterPublicKey = ''
2021-12-25 14:39:47 +01:00
/**
* Testnet Master Private Key (Base58 encoded) - THIS IS TESTNET
*/
2021-12-25 14:39:47 +01:00
this._tMasterPrivateKey = ''
2021-12-25 14:39:47 +01:00
/**
* Testnet Master Public Key (Base58 encoded) - THIS IS TESTNET
*/
2021-12-25 14:39:47 +01:00
this._tmasterPublicKey = ''
2021-12-25 14:39:47 +01:00
/**
* Child Keys Derivation from the Parent Keys
*/
2021-12-25 14:39:47 +01:00
/**
* Child Private Key - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.childPrivateKey = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Child Chain Code - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.childChainCode = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Child Public Key - 33 bytes (compressed)
*/
2021-12-25 14:39:47 +01:00
this.childPublicKey = new Uint8Array(33)
2021-12-25 14:39:47 +01:00
/**
* Child Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
2021-12-25 14:39:47 +01:00
this.childPublicKeyHash = new Uint8Array(20)
2021-12-25 14:39:47 +01:00
/**
* Extended Private Child Key - Base58 encoded
*/
2021-12-25 14:39:47 +01:00
this.xPrivateChildKey = ''
2021-12-25 14:39:47 +01:00
/**
* Extended Public Child Key - Base58 encoded
*/
2021-12-25 14:39:47 +01:00
this.xPublicChildKey = ''
2021-12-25 14:39:47 +01:00
/**
* Grand Child Keys Derivation from the Child Keys
*/
2021-12-25 14:39:47 +01:00
/**
* Grand Child Private Key - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.grandChildPrivateKey = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Grand Child Chain Code - 32 bytes
*/
2021-12-25 14:39:47 +01:00
this.grandChildChainCode = new Uint8Array(32)
2021-12-25 14:39:47 +01:00
/**
* Grand Child Public Key - 33 bytes (compressed)
*/
2021-12-25 14:39:47 +01:00
this.grandChildPublicKey = new Uint8Array(33)
2021-12-25 14:39:47 +01:00
/**
* Grand Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
2021-12-25 14:39:47 +01:00
this.grandChildPublicKeyHash = new Uint8Array(20)
2021-12-25 14:39:47 +01:00
/**
* Extended Private Grand Child Key - Base58 encoded
*/
2021-12-25 14:39:47 +01:00
this.xPrivateGrandChildKey = ''
2021-12-25 14:39:47 +01:00
/**
* Extended Public Grand Child Key - Base58 encoded
*/
2021-12-25 14:39:47 +01:00
this.xPublicGrandChildKey = ''
2021-12-25 14:39:47 +01:00
/**
* Litecoin Legacy Address - Derived from the Grand Child Public Key Hash
*/
2021-12-25 14:39:47 +01:00
this.litecoinLegacyAddress = ''
2021-12-25 14:39:47 +01:00
/**
* TESTNET Litecoin Legacy Address (Derived from the Grand Child Public Key Hash) - THIS IS TESTNET
*/
2021-12-25 14:39:47 +01:00
this._tlitecoinLegacyAddress = ''
2021-12-25 14:39:47 +01:00
/**
* Wallet - Wallet Object (keys...)
*/
2021-12-25 14:39:47 +01:00
this.wallet = {}
}
2021-12-25 14:39:47 +01:00
setSeed(seed) {
this.seed = seed
}
2021-12-25 14:39:47 +01:00
createWallet(seed, isBIP44, indicator = null) {
2021-12-25 14:39:47 +01:00
// Set Seeed
this.setSeed(seed)
2021-12-25 14:39:47 +01:00
// Generate Seed Hash
this.generateSeedHash(this.seed, isBIP44, indicator)
2021-12-25 14:39:47 +01:00
// Generate Private Key
this.generatePrivateKey(this.seedHash)
2021-12-25 14:39:47 +01:00
// Generate Chain Code
this.generateChainCode(this.seedHash)
2021-12-25 14:39:47 +01:00
// Generate Public Key from Private Key
this.generatePublicKey(this.privateKey)
2021-12-25 14:39:47 +01:00
// Generate Mainnet Master Private Key
this.generateMainnetMasterPrivateKey()
2021-12-25 14:39:47 +01:00
// Generate Mainnet Master Public Key
this.generateMainnetMasterPublicKey()
2021-12-25 14:39:47 +01:00
// Generate Testnet Master Private Key
this.generateTestnetMasterPrivateKey()
2021-12-25 14:39:47 +01:00
// Generate Testnet Master Public Key
this.generateTestnetMasterPublicKey()
2021-12-25 14:39:47 +01:00
// Generate Child and Grand Child Keys
this.generateDerivedChildKeys()
2021-12-25 14:39:47 +01:00
// Return Wallet Object Specification
return this.returnWallet()
}
2021-12-25 14:39:47 +01:00
generateSeedHash(seed, isBIP44, indicator = null) {
let buffer
2021-12-25 14:39:47 +01:00
if (isBIP44) {
buffer = utils.appendBuffer(seed.reverse(), utils.int32ToBytes(indicator))
} else {
if (indicator !== null) {
const indicatorString = utils.stringtoUTF8Array(indicator)
buffer = utils.appendBuffer(seed.reverse(), indicatorString)
}
else {
buffer = seed.reverse()
}
}
2021-12-25 14:39:47 +01:00
const _reverseSeedHash = new Sha256().process(buffer).finish().result
this.seedHash = new Sha512().process(utils.appendBuffer(seed, _reverseSeedHash)).finish().result
}
2021-12-25 14:39:47 +01:00
generatePrivateKey(seedHash) {
const SECP256K1_CURVE_ORDER = new BigInteger("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
2021-12-25 14:39:47 +01:00
const privateKeyHash = seedHash.slice(0, 32)
2021-12-25 14:39:47 +01:00
this.seed58 = Base58.encode(privateKeyHash)
const _privateKeyHash = [...privateKeyHash]
let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash)
2021-12-25 14:39:47 +01:00
const privateKey = (privateKeyBigInt.mod(SECP256K1_CURVE_ORDER.subtract(BigInteger.ONE))).add(BigInteger.ONE)
this.privateKey = privateKey.toByteArrayUnsigned()
}
2021-12-25 14:39:47 +01:00
generateChainCode(seedHash) {
this.chainCode = new Sha256().process(seedHash.slice(32, 64)).finish().result
}
2021-12-25 14:39:47 +01:00
generatePublicKey(privateKey) {
const _privateKey = [...privateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
2021-12-25 14:39:47 +01:00
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
2021-12-25 14:39:47 +01:00
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
2021-12-25 14:39:47 +01:00
/**
* Deriving Uncompressed Public Key (65 bytes)
*
* const publicKeyBytes = EllipticCurve.integerToBytes(x, 32)
* this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32))
* this.publicKey.unshift(0x04) // append point indicator
*/
2021-12-25 14:39:47 +01:00
// Compressed Public Key (33 bytes)
this.publicKey = EllipticCurve.integerToBytes(x, 32)
2021-12-25 14:39:47 +01:00
if (y.isEven()) {
this.publicKey.unshift(0x02) // append point indicator
} else {
this.publicKey.unshift(0x03) // append point indicator
}
2021-12-25 14:39:47 +01:00
// PublicKey Hash
const publicKeySHA256 = new Sha256().process(new Uint8Array(this.publicKey)).finish().result
2024-03-29 09:00:10 +01:00
this.publicKeyHash = new RIPEMD160().update(Buffer.from(publicKeySHA256)).digest('hex')
}
2021-12-25 14:39:47 +01:00
generateMainnetMasterPrivateKey() {
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
2021-12-25 14:39:47 +01:00
// Append Depth
s.push(this.depth)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
2021-12-25 14:39:47 +01:00
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.chainCode)
2021-12-25 14:39:47 +01:00
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
2021-12-25 14:39:47 +01:00
//if the private key length is less than 32 let's add leading zeros
if (this.privateKey.length < 32) {
for (let i = this.privateKey.length; i < 32; i++) {
s.push(0)
}
}
2021-12-25 14:39:47 +01:00
// Append Private Key
s.push(...this.privateKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Private Key as Base58 encoded
this.masterPrivateKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
generateMainnetMasterPublicKey() {
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
2021-12-25 14:39:47 +01:00
// Append Depth
s.push(this.depth)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
2021-12-25 14:39:47 +01:00
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.chainCode)
2021-12-25 14:39:47 +01:00
// Append Public Key
s.push(...this.publicKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Public Key as Base58 encoded
this.masterPublicKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
generateTestnetMasterPrivateKey() {
2021-12-25 14:39:47 +01:00
// To be Used ONLY in Testnet...
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.private)))
2021-12-25 14:39:47 +01:00
// Append Depth
s.push(this.depth)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
2021-12-25 14:39:47 +01:00
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.chainCode)
2021-12-25 14:39:47 +01:00
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
2021-12-25 14:39:47 +01:00
// Append Private Key
s.push(...this.privateKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Private Key as Base58 encoded
this._tMasterPrivateKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
generateTestnetMasterPublicKey() {
2021-12-25 14:39:47 +01:00
// To be Used ONLY in Testnet...
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.public)))
2021-12-25 14:39:47 +01:00
// Append Depth
s.push(this.depth)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
2021-12-25 14:39:47 +01:00
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.chainCode)
2021-12-25 14:39:47 +01:00
// Append Private Key
s.push(...this.publicKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Private Key as Base58 encoded
this._tmasterPublicKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
generateDerivedChildKeys() {
2021-12-25 14:39:47 +01:00
// SPEC INFO: https://en.bitcoin.it/wiki/BIP_0032#Child_key_derivation_.28CKD.29_functions
// NOTE: will not be using some of derivations func as the value is known. (So I'd rather shove in the values and rewrite out the derivations later ?)
2021-12-25 14:39:47 +01:00
// NOTE: I "re-wrote" and "reduplicate" the code for child and grandChild keys derivations inorder to get the child and grandchild from the child
// TODO: Make this more better in the future
2021-12-25 14:39:47 +01:00
const path = 'm/0/0'
// let p = path.split('/')
2021-12-25 14:39:47 +01:00
// Get Public kEY
const derivePublicChildKey = () => {
2021-12-25 14:39:47 +01:00
const _privateKey = [...this.childPrivateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
2021-12-25 14:39:47 +01:00
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
2021-12-25 14:39:47 +01:00
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
2021-12-25 14:39:47 +01:00
// Compressed Public Key (33 bytes)
this.childPublicKey = EllipticCurve.integerToBytes(x, 32)
2021-12-25 14:39:47 +01:00
if (y.isEven()) {
2021-12-25 14:39:47 +01:00
this.childPublicKey.unshift(0x02) // append point indicator
} else {
2021-12-25 14:39:47 +01:00
this.childPublicKey.unshift(0x03) // append point indicator
}
2021-12-25 14:39:47 +01:00
// PublicKey Hash
const childPublicKeySHA256 = new Sha256().process(new Uint8Array(this.childPublicKey)).finish().result
2024-03-29 09:00:10 +01:00
this.childPublicKeyHash = new RIPEMD160().update(Buffer.from(childPublicKeySHA256)).digest('hex')
2021-12-25 14:39:47 +01:00
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicChildKey(1, 0)
}
2021-12-25 14:39:47 +01:00
const derivePrivateChildKey = (cI) => {
2021-12-25 14:39:47 +01:00
let ib = []
ib.push((cI >> 24) & 0xff)
ib.push((cI >> 16) & 0xff)
ib.push((cI >> 8) & 0xff)
ib.push(cI & 0xff)
2021-12-25 14:39:47 +01:00
const s = [...this.publicKey].concat(ib)
2021-12-25 14:39:47 +01:00
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.chainCode, format: "UINT8ARRAY" } })
_hmacSha512.update(new Uint8Array(s))
2021-12-25 14:39:47 +01:00
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
this.childChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
2021-12-25 14:39:47 +01:00
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
2021-12-25 14:39:47 +01:00
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
this.childPrivateKey = ki.toByteArrayUnsigned()
2021-12-25 14:39:47 +01:00
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateChildKey(1, 0)
}
2021-12-25 14:39:47 +01:00
const deriveExtendedPrivateChildKey = (i, childIndex) => {
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
2021-12-25 14:39:47 +01:00
// Append Depth (using the index as depth)
i = parseInt(i)
s.push(i)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(this.publicKeyHash.slice(0, 4)))
2021-12-25 14:39:47 +01:00
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.childChainCode)
2021-12-25 14:39:47 +01:00
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
2021-12-25 14:39:47 +01:00
// Append Private Key
s.push(...this.childPrivateKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Private Key as Base58 encoded
this.xPrivateChildKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
const deriveExtendedPublicChildKey = (i, childIndex) => {
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
2021-12-25 14:39:47 +01:00
// Append Depth
i = parseInt(i)
s.push(i)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(this.publicKeyHash.slice(0, 4)))
2021-12-25 14:39:47 +01:00
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.childChainCode)
2021-12-25 14:39:47 +01:00
// Append Public Key
s.push(...this.childPublicKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Public Key as Base58 encoded
this.xPublicChildKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
/**
* GRAND CHILD KEYS
*
* NOTE: I know this is not the best way to generate this (even though it works the way it ought)
* Things to rewrite will be and not limited to deriving this through a for loop, removing hard code values, etc...
*/
2021-12-25 14:39:47 +01:00
const derivePublicGrandChildKey = () => {
2021-12-25 14:39:47 +01:00
const _privateKey = [...this.grandChildPrivateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
2021-12-25 14:39:47 +01:00
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
2021-12-25 14:39:47 +01:00
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
2021-12-25 14:39:47 +01:00
// Compressed Public Key (33 bytes)
this.grandChildPublicKey = EllipticCurve.integerToBytes(x, 32)
2021-12-25 14:39:47 +01:00
if (y.isEven()) {
this.grandChildPublicKey.unshift(0x02) // append point indicator
} else {
this.grandChildPublicKey.unshift(0x03) // append point indicator
}
2021-12-25 14:39:47 +01:00
// PublicKey Hash
const grandChildPublicKeySHA256 = new Sha256().process(new Uint8Array(this.grandChildPublicKey)).finish().result
2024-03-29 09:00:10 +01:00
this.grandChildPublicKeyHash = new RIPEMD160().update(Buffer.from(grandChildPublicKeySHA256)).digest('hex')
2021-12-25 14:39:47 +01:00
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicGrandChildKey(2, 0)
2021-12-25 14:39:47 +01:00
/**
* Derive Litecoin Legacy Address
*/
2021-12-25 14:39:47 +01:00
// Append Address Prefix
let prefix = [this.versionBytes.mainnet.prefix]
if (2 == this.versionBytes.mainnet.prefix.length) {
prefix = [this.versionBytes.mainnet.prefix[0]]
prefix.push([this.versionBytes.mainnet.prefix[1]])
}
2021-12-25 14:39:47 +01:00
const k = prefix.concat(...this.grandChildPublicKeyHash)
2021-12-25 14:39:47 +01:00
// Derive Checksum
const _addressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(k)).finish().result).finish().result
const addressCheckSum = _addressCheckSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
const _litecoinLegacyAddress = k.concat(...addressCheckSum)
2021-12-25 14:39:47 +01:00
// Convert to Base58
this.litecoinLegacyAddress = Base58.encode(_litecoinLegacyAddress)
2021-12-25 14:39:47 +01:00
/**
* Derive TESTNET Litecoin Legacy Address
*/
2021-12-25 14:39:47 +01:00
// Append Version Byte
const tK = [this.versionBytes.testnet.prefix].concat(...this.grandChildPublicKeyHash)
2021-12-25 14:39:47 +01:00
// Derive Checksum
const _tAddressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(tK)).finish().result).finish().result
const tAddressCheckSum = _tAddressCheckSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
const _tlitecoinLegacyAddress = tK.concat(...tAddressCheckSum)
2021-12-25 14:39:47 +01:00
// Convert to Base58
this._tlitecoinLegacyAddress = Base58.encode(_tlitecoinLegacyAddress)
}
2021-12-25 14:39:47 +01:00
const derivePrivateGrandChildKey = (cI, i) => {
2021-12-25 14:39:47 +01:00
let ib = []
ib.push((cI >> 24) & 0xff)
ib.push((cI >> 16) & 0xff)
ib.push((cI >> 8) & 0xff)
ib.push(cI & 0xff)
2021-12-25 14:39:47 +01:00
const s = [...this.childPublicKey].concat(ib)
2021-12-25 14:39:47 +01:00
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.childChainCode, format: "UINT8ARRAY" } })
_hmacSha512.update(new Uint8Array(s))
2021-12-25 14:39:47 +01:00
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
this.grandChildChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
2021-12-25 14:39:47 +01:00
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
2021-12-25 14:39:47 +01:00
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.childPrivateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
this.grandChildPrivateKey = ki.toByteArrayUnsigned()
2021-12-25 14:39:47 +01:00
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateGrandChildKey(2, 0)
}
2021-12-25 14:39:47 +01:00
const deriveExtendedPrivateGrandChildKey = (i, childIndex) => {
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
2021-12-25 14:39:47 +01:00
// Append Depth (using the index as depth)
i = parseInt(i)
s.push(i)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(this.childPublicKeyHash.slice(0, 4)))
2021-12-25 14:39:47 +01:00
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.grandChildChainCode)
2021-12-25 14:39:47 +01:00
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
2021-12-25 14:39:47 +01:00
// Append Private Key
s.push(...this.grandChildPrivateKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Private Key as Base58 encoded
this.xPrivateGrandChildKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
const deriveExtendedPublicGrandChildKey = (i, childIndex) => {
2021-12-25 14:39:47 +01:00
// Serialization Variable
const s = []
2021-12-25 14:39:47 +01:00
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
2021-12-25 14:39:47 +01:00
// Append Depth
i = parseInt(i)
s.push(i)
2021-12-25 14:39:47 +01:00
// Append Parent Fingerprint
s.push(...(this.childPublicKeyHash.slice(0, 4)))
2021-12-25 14:39:47 +01:00
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
2021-12-25 14:39:47 +01:00
// Append Chain Code
s.push(...this.grandChildChainCode)
2021-12-25 14:39:47 +01:00
// Append Public Key
s.push(...this.grandChildPublicKey)
2021-12-25 14:39:47 +01:00
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
2021-12-25 14:39:47 +01:00
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
2021-12-25 14:39:47 +01:00
// Save to Public Key as Base58 encoded
this.xPublicGrandChildKey = Base58.encode(s)
}
2021-12-25 14:39:47 +01:00
// Hard Code value..
let childIndex = 0
2021-12-25 14:39:47 +01:00
// Call derivePrivateChildKey //Hard code value
derivePrivateChildKey(childIndex)
2021-12-25 14:39:47 +01:00
// Call derivePublicChildKey
derivePublicChildKey()
2021-12-25 14:39:47 +01:00
// Call derivePrivateGrandChildKey // Hard Code value...
derivePrivateGrandChildKey(0, 2)
2021-12-25 14:39:47 +01:00
// Call derivePublicGrandChildKey
derivePublicGrandChildKey()
}
2021-12-25 14:39:47 +01:00
returnWallet() {
2021-12-25 14:39:47 +01:00
// Will be limiting the exported Wallet Object to just the Master keys and Legacy Addresses
2021-12-25 14:39:47 +01:00
const wallet = {
derivedMasterPrivateKey: this.masterPrivateKey,
derivedMasterPublicKey: this.masterPublicKey,
_tDerivedMasterPrivateKey: this._tMasterPrivateKey,
_tDerivedmasterPublicKey: this._tmasterPublicKey,
seed58: this.seed58,
address: this.litecoinLegacyAddress,
_taddress: this._tlitecoinLegacyAddress
}
2021-12-25 14:39:47 +01:00
this.wallet = wallet
return wallet
}
2021-12-25 14:39:47 +01:00
}