Generating address from ExtendedPublicKey
Closed this issue · 4 comments
Hi,
Is it possible to generate address directly from the ExtendedPublicKey you get from appAda.getExtendedPublicKey()
?
I mean, instead of querying Ledger for new address multiple times, can Ledger be queried for the ExtendedPublicKey, and then addresses derived from that without having to query the ledger.
appAda.getExtendedPublicKey().deriveAddress()
-> utils.bech32_encodeAddress()
Thanks in advance.
Hi @Zireael, this library is intended just as a thin wrapper over Ledger's calls, nevertheless, you can obtain the account public key (1852'/1815'/<account index>'
for Shelley or 44'/1815'/<account index>'
for Byron addresses), derive the respective child public keys which involves only non-hardened derivation (i.e. no knowledge of parent private key required) and assemble the addresses without further interaction with Ledger.
You can use e.g. cardano-serialization-lib for that https://github.com/Emurgo/cardano-serialization-lib/blob/master/doc/getting-started/generating-keys.md
Thanks, I got the cardano-serialization working and with ledgerjs-cardano-shelley am able to export the public key in two parts:
{
publicKeyHex: 'e6cb70c56fffffffffffffffffffffffffffffffffffffffffffffffffff',
chainCodeHex: '1fadcf740ffffffffffffffffffffffffffffffffffffffffffffffffffff'
}
However cardano-serialization expects the public key in the format 'xpub6DLjthA5JrEnopfffffffffffffffffffffffffffffffffff' and I can't figure out how to do the conversion.
From what I gather, public key is 64-byte: the 32-byte ED25519 public key plus the 32-byte chain code of the public key. How do I construct that?
"xpub" + publicKeyHex + chainCodeHex
?
Something like this?
const rootKey = CardanoWASM.Bip32PublicKey.from_bytes(
Buffer.from(
"e6cb70c56fffffffffffffffffffffffffffffffffffffffffffffffffff" +
"1fadcf740ffffffffffffffffffffffffffffffffffffffffffffffffffff",
"hex"
)
);
I checked in runkit and the extended public key as a buffer seems to work fine:
const csl = require("@emurgo/cardano-serialization-lib-nodejs")
const rootKey = csl.Bip32PublicKey.from_bytes(
Buffer.from(
"e6ab70c569d8c47bef9b0c01b54c1a0c19dfc6d8fef5957a0a68cb78f8fa64a5" +
"1faacf74053f64e9109d4b36fa9702e1b0e392a06524e6d0d69f5465dcf58d4f",
"hex"
)
); // account (m/1852'/1815'/0') key obtained from ledger (presumably)
const paymentKey = rootKey
.derive(0) // visible address
.derive(0) // address index 0
.to_raw_key();
const stakeKey = rootKey
.derive(2) // staking chain
.derive(0) // fixed value for staking keys for given account
.to_raw_key();
const addr = csl.BaseAddress.new(
1, // mainnet chain
csl.StakeCredential.from_keyhash(paymentKey.hash()),
csl.StakeCredential.from_keyhash(stakeKey.hash())
).to_address();
console.log(addr.to_bytes());
console.log(addr.to_bech32());
You can look up up in Yoroi codebase how child keys are derived and addresses are obtained from the keys https://github.com/Emurgo/yoroi-frontend/blob/2fd4541b5745601dcfa36fde56873d67012dcbfa/app/api/ada/lib/cardanoCrypto/plate.js#L75
And you can use then Ledger's deriveAddress
call to sanity-check your results.
Disclaimer - I'm not that familiar with cardano-serialization-lib as I use cardano-crypto.js in my projects which has a lower level api, so there may be errors in the implementation above, however the general idea should be right and you can easily sanity-check your results with Ledger.
Thanks, this seems to work ^^