hedera-sdk-js: Mnemonics -> ECDSA key -> ECDSA key doesn't yield same public key

Description

I’m recovering a private key from Mnemonics and printing the public key as a string. I then use the private key string above to instantiate a PrivateKey and print its public key as a string. The two public keys differ, yet printing both private keys as string yield the same result, see example below

Steps to reproduce

import {
    Mnemonic, PrivateKey,
} from "@hashgraph/sdk";

async function test() {
    const mnemonic = await Mnemonic.fromString("hamster produce dry base sunny bubble disease throw cricket garden beyond script");
    const privateKey = await mnemonic.toEcdsaPrivateKey();

    const privateKeyString = privateKey.toStringRaw();
    const publicKeyString = privateKey.publicKey.toStringRaw();

    // Restore from string
    const restoredPrivateKey = PrivateKey.fromStringECDSA(privateKeyString);
    const restoredPrivateKeyString = privateKey.toStringRaw();
    const restoredPublicKeyString = restoredPrivateKey.publicKey.toStringRaw();

    const results = {
      FromMnemonics: {Private: privateKeyString, Public: publicKeyString},
      ECDSA: {Private: restoredPrivateKeyString, Public: restoredPublicKeyString}
    };
    console.table(results);

}

test();

outputs

┌───────────────┬────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────┐
│    (index)    │                              Private                               │                                Public                                │
├───────────────┼────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┤
│ FromMnemonics │ '63167e08a41aaaa8226945b999a201f789e1a362d4d5b93d605e0841795eb500' │ '0322c1cc8bdbdd54b851251a61ea98d4da31f2749f00e44d66efc2295df76b4a9a' │
│     ECDSA     │ '63167e08a41aaaa8226945b999a201f789e1a362d4d5b93d605e0841795eb500' │ '0283ddc3dfca5dab9c10b4a6be831bae1b50ab36224c305bdd008c6042b34b3123' │
└───────────────┴────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────┘

Shouldn’t both public keys be the same ?

Note, investigating through debugging the SDK shows that the two private keys differ slightly, see below

First key (from mnemonics - chaincode attribute value removed)

{ "_key": { "_keyPair": { "privateKey": { "type": "Buffer", "data": [ 99, 22,
126, 8, 164, 26, 170, 168, 34, 105, 69, 185, 153, 162, 1, 247, 137, 225, 163,
98, 212, 213, 185, 61, 96, 94, 8, 65, 121, 94, 181 ] }, 
"publicKey": { "type":
"Buffer", "data": [ 3, 34, 193, 204, 139, 219, 221, 84, 184, 81, 37, 26, 97,
234, 152, 212, 218, 49, 242, 116, 159, 0, 228, 77, 102, 239, 194, 41, 93, 247,
107, 74, 154 ] } }
  }

Second key (fromStringECDSA)

Second _key { "_keyPair": { "privateKey": { "type": "Buffer", "data": [ 99, 22,
126, 8, 164, 26, 170, 168, 34, 105, 69, 185, 153, 162, 1, 247, 137, 225, 163,
98, 212, 213, 185, 61, 96, 94, 8, 65, 121, 94, 181, 0 ] },
"publicKey": {
"type": "Buffer", "data": [ 2, 131, 221, 195, 223, 202, 93, 171, 156, 16, 180,
166, 190, 131, 27, 174, 27, 80, 171, 54, 34, 76, 48, 91, 221, 0, 140, 96, 66,
179, 75, 49, 35 ] } }, "_chainCode": null
}

note that the first contains an extra element at the end of the buffer 0, the public key buffer is vastly different.

Additional context

No response

Hedera network

mainnet, testnet, previewnet

Version

v2.19.1 and 2.19.0

Operating system

None

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 20 (14 by maintainers)

Most upvoted comments

@alittley Short update The functionality from the library did not work, so I’ve implemented the zero padding in the SDK itself. I also added an ecdsa generation from a specific mnemonic with the default ethereum derivation path 44'/60'/0'/0/0 which is used to test in ethers.js as well. Everything is pushed in the same branch so you can check it

@alittley That’s why we put the PR in draft. We are on the same page that when we clarify the reason, we need to include the fix in the Epic for the Mnemonic refactor. @petreze is still researching it.