vechain / vechain-sdk-js

The official JavaScript SDK for VeChain.
24 stars 9 forks source link

Investigate pbkdf2 #1334

Closed fabiorigam closed 2 weeks ago

fabiorigam commented 3 weeks ago

Investigate if it's possible to implement pbkdf2 (used mostly on mobile).

lucanicoladebiasi commented 2 weeks ago

The use of PBKDF2 derives a randomised seed from mnemonic words good enough to seed SECP256K1 key pard generation, but is not at all simpler or quicker than any other method developed in the last 20 years.

However - because implemented in many hardware - it could be convenient to have in the SDK. This is possible because the library noble-hash we use in the SDK provides the needed functionalities.

lucanicoladebiasi commented 2 weeks ago

I applied the blackbox approach to compare mnemonic input to wished output. @grenos instructed me 'west liberty trash promote cushion install have coast color parade receive wire should resunt in the address 0x88471b80cac83d549843ce96f20aff3a00f219b4. Hence I worte the following snippet based of this SDK

import { Address } from '@vechain/sdk-core';
const mnemonics =
    'west liberty trash promote cushion install have coast color parade receive wire'.split(
        ' '
    );
const address = Address.ofMnemonic(mnemonics);
console.log(address.toString());

getting as result 0x88471b80CAC83d549843cE96f20afF3A00F219B4 that is the expected address. This proves the SDK address implementation internally uses (the evolution) of the (25 years old) PDKDF2 algorithm

The chain to derive address from mnemonics is the following:

  1. mnemonics -> PDKDF2 -> pseudo-random seed (PDKDF2 is an hashing algorithm);
  2. random seed - > SECP256K1 -> private and public keys
  3. public key -> KECCAK256 -> address.

Hence, there is no need to provide PDKF2 API in the SDK because the needed functionalities are already provided by the Address class. The Mnemonic class provided methods to derive the public key from mnemonics.

lucanicoladebiasi commented 2 weeks ago

The experiment above demonstrates long computational times experienced in some runtime are not caused by the SDK implementation. The SDK uses the audited libraries noble-curves and noble-hash, the latter providing PBKDF2. The named libraries delegates cryptography math to the crypto component of NodeJS runtime, the crypto component delegated the functionalities to the API of the operating system, this one provides the call to the hardware random generator. If NodeJS runtime can't bind with crypto as expected, the SDK implements a fall back mechanism running the cryptographic math with only what JS runtime provides, this is why it's many orders of magnitude slower than the same math delegated to the hardware through the OS. Unfortunately this can be the case when the runtime is hosted by a mobile architecture.

JS React allows JS code to call a sandbox running code compiled in C/C++. Facebook uses this approach to implement PBKDF2. I'm investigating how to plug in the https://github.com/margelo/react-native-quick-crypto/tree/main/packages/react-native-quick-crypto project the C++ PBKDF2 library to seed the C++ SECP256K1 library to input the C++ KECCK256 library to obtain the address from mnemonics. This is the Facebook suggested pattern to have cryptography safely and fast implemented.

The Bitcoin Foundation published the required C/C++ libraries I'm investigating.

lucanicoladebiasi commented 2 weeks ago

Experimenting with the MIT licensed C++ source code published at https://github.com/edwardstock/bip3x. Successfully compiled for MacOS on ARM architecture thanks to https://www.jetbrains.com/clion/.

Shortcut to compile the cryptographic shared library to call from C/C++

  1. Install CMake.
    brew install cmake
  2. From the directory where bip3x is installed
    mkdir build & cd build
  3. Compile the library to be called from C/C++ code
    cmake .. -DCMAKE_BUILD=Release -Dbip3x_BUILD_SHARED_LIBS=On -Dbip3x_BUILD_JNI_BINDINGS=Off -Dbip3x_BUILD_C_BINDINGS=On -Dbip3x_BUILD_TESTS=Off