简体   繁体   English

关于使用 xpub 和 Zcash 路径自动派生地址的问题

[英]A question regarding automated derivation of addresses using xpub and path for Zcash

I'm currently developing an API for my company which utilizes xpub and path to generate an address.我目前正在为我的公司开发一个 API,它利用 xpub 和路径生成地址。

Thing is, I managed to do that for all cryptocurrencies we require except for Zcash.问题是,我设法为我们需要的所有加密货币做到了这一点,除了 Zcash。 We're using trezor hardware wallet and Trezor connect doesn't work for us, since we need the flow to be detached from device itself.我们使用的是 Trezor 硬件钱包,而 Trezor connect 对我们不起作用,因为我们需要将流与设备本身分离。

Generally, I'm using bitcoinjs library for all other coins, yet I couldn't derive the right address format for zcash.通常,我对所有其他硬币使用 bitcoinjs 库,但我无法为 zcash 导出正确的地址格式。 Spent quite a lot of time searching in github issues, but no luck.花了很多时间搜索 github 问题,但没有运气。 A word of help would be really great, thanks guys: My code currently looks like this:一句帮助真的很棒,谢谢大家:我的代码目前看起来像这样:

xpub = process.env.ZEC_PUB_KEY;
network = {
messagePrefix: '\x18ZCash Signed Message:\n',
bech32: 't1',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x1cb8,
scriptHash: 0x1cbd,
wif: 0x80
};
p2wpkh = bjs.payments.p2wpkh({ pubkey: bjs.bip32.fromBase58(xpub, network).derive(0).derive(pathNumber).publicKey, network });
payment = bjs.payments.p2sh({ redeem: p2wpkh, network });
address = payment.address;

So, turns out I've found the answer, required some reading on weird resources.所以,事实证明我找到了答案,需要阅读一些奇怪的资源。 Hope this will help you.希望这会帮助你。

First thing, zcash is not SegWit compatible, therefore the p2wpkh function won't work for this, you should use p2pkh.首先,zcash 不兼容 SegWit,因此 p2wpkh function 不适用于此,您应该使用 p2pkh。 The p2sh method call is also redundant here, so the code will look something like this: p2sh 方法调用在这里也是多余的,所以代码看起来像这样:

network = {
messagePrefix: '\x18ZCash Signed Message:\n',
bech32: 't1',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x1cb8,
scriptHash: 0x1cbd,
wif: 0x80
};
payment= bjs.payments.p2pkh({ pubkey: bjs.bip32.fromBase58(xpub, network).derive(0).derive(pathNumber).publicKey, network });
address = payment.address;

Also, bitcoinjs-lib library doesn't support altcoins in some ways.此外,bitcoinjs-lib 库在某些方面不支持山寨币。 In this case, the p2pkh function utilizes toUint8 in it's core, so you can basically fork the repo and update that method to use a data type of broader boundaries, toUint16LE.在这种情况下,p2pkh function 在其核心中使用 toUint8,因此您基本上可以分叉存储库并更新该方法以使用边界更广泛的数据类型 toUint16LE。

Afterwards, the function will return a bitcoin address, but we need zcash.之后,function 会返回一个比特币地址,但我们需要 zcash。 We can easily convert it by using the following function:我们可以使用以下 function 轻松转换它:

function baddrToTaddr(baddr_str) {
var baddr = bs58check.decode(baddr_str).slice(1);  // discard type byte
var taddr = new Uint8Array(22);
taddr.set(baddr, 2);
taddr.set([0x1c,0xb8], 0);  // set zcash type bytes
return bs58check.encode(Buffer.from(taddr));
}

That's it.而已。

I used the solution first posted by Lasha Lomidze and built on top of that a little bit.我使用了 Lasha Lomidze 首先发布的解决方案,并在此基础上进行了一些构建。 I had a requirement to keep the default package the same, so I had to recreate the hash160 function used.我需要保持默认的 package 相同,所以我必须重新创建使用的 hash160 function。 I was then able to simplify the P2PKH address script function a little bit see below.然后我能够稍微简化 P2PKH 地址脚本 function,见下文。 Notice I use writeUInt16BE to correctly write the pubKeyHash vs writeUInt16LE due to the order in which the bytes are written:请注意,由于字节的写入顺序,我使用 writeUInt16BE 正确写入 pubKeyHash vs writeUInt16LE:

function getP2PKHAddress2BytePubKeyHash(pubkey: Buffer, network: Network): string{
    // allocate 22 bytes instead of bitcoinlib-js 21
    const payload = Buffer.allocUnsafe(22)
    // write UInt16BE to make use of the network
    // pubKeyHash
    payload.writeUInt16BE(network.pubKeyHash, 0)
    
    // hash the pubkey and copy starting at position 2
    // because the writeUInt16BE writes to two bytes
    const hashVal = crypto.hash160(pubkey)
    hashVal.copy(payload, 2)

    // return payload with bs58 encoding
    return bs58check.encode(payload)
}

The below items I put in a file called crypto.ts and exported the hash160 function to be used by the above function.我将以下项目放入名为 crypto.ts 的文件中并导出 hash160 function 以供上述 function 使用。

export {}
const createHash = require('create-hash')

function ripemd160(buffer: Buffer): Buffer {
    try {
      return createHash('rmd160').update(buffer).digest()
    } catch (err) {
      return createHash('ripemd160').update(buffer).digest()
    }
}
function sha256(buffer: Buffer): Buffer {
    return createHash('sha256').update(buffer).digest()
}

export function hash160(buffer: Buffer): Buffer {
    return ripemd160(sha256(buffer))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM