Skip to content

Commit

Permalink
Add additional cryptography test vectors (#200)
Browse files Browse the repository at this point in the history
Signed-off-by: Rob Walworth <[email protected]>
  • Loading branch information
rwalworth authored Feb 10, 2023
1 parent 3635180 commit 5f4154b
Show file tree
Hide file tree
Showing 9 changed files with 570 additions and 189 deletions.
4 changes: 2 additions & 2 deletions sdk/main/include/MnemonicBIP39.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class MnemonicBIP39 : public Mnemonic
* @throws std::invalid_argument If the index is already hardened.
*/
[[nodiscard]] std::unique_ptr<ED25519PrivateKey> toStandardEd25519PrivateKey(const std::string& passphrase = "",
int index = 0) const;
uint32_t index = 0) const;

/**
* Generate an ECDSAsecp256k1PrivateKey from this Mnemonic using the input passphrase at the specified index.
Expand All @@ -106,7 +106,7 @@ class MnemonicBIP39 : public Mnemonic
*/
[[nodiscard]] std::unique_ptr<ECDSAsecp256k1PrivateKey> toStandardECDSAsecp256k1PrivateKey(
const std::string& passphrase = "",
int index = 0) const;
uint32_t index = 0) const;

/**
* Compute a seed that results from this MnemonicBIP39.
Expand Down
8 changes: 4 additions & 4 deletions sdk/main/src/MnemonicBIP39.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,18 @@ MnemonicBIP39 MnemonicBIP39::generate24WordBIP39Mnemonic()

//-----
std::unique_ptr<ED25519PrivateKey> MnemonicBIP39::toStandardEd25519PrivateKey(const std::string& passphrase,
int index) const
uint32_t index) const
{
return ED25519PrivateKey::fromSeed(toSeed(passphrase))->derive(40)->derive(3030)->derive(0)->derive(0)->derive(index);
return ED25519PrivateKey::fromSeed(toSeed(passphrase))->derive(44)->derive(3030)->derive(0)->derive(0)->derive(index);
}

//-----
std::unique_ptr<ECDSAsecp256k1PrivateKey> MnemonicBIP39::toStandardECDSAsecp256k1PrivateKey(
const std::string& passphrase,
int index) const
uint32_t index) const
{
return ECDSAsecp256k1PrivateKey::fromSeed(toSeed(passphrase))
->derive(internal::DerivationPathUtils::getHardenedIndex(40))
->derive(internal::DerivationPathUtils::getHardenedIndex(44))
->derive(internal::DerivationPathUtils::getHardenedIndex(3030))
->derive(internal::DerivationPathUtils::getHardenedIndex(0))
->derive(0)
Expand Down
8 changes: 6 additions & 2 deletions sdk/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,19 @@ add_executable(${TEST_PROJECT_NAME}
EvmAddressTest.cc
ExchangeRateTest.cc
HbarTest.cc
MnemonicBIP39Test.cc
TransactionIdTest.cc
TransactionReceiptQueryTest.cc
TransactionReceiptTest.cc
TransactionRecordQueryTest.cc
TransactionRecordTest.cc
TransactionResponseTest.cc
TransferTest.cc
TransferTransactionTest.cc)
TransferTransactionTest.cc

vectors/BIP39TestVectors.cc
vectors/Hedera12WordMnemonicBIP39TestVectors.cc
vectors/Hedera24WordMnemonicBIP39TestVectors.cc
vectors/SLIP10TestVectors.cc)

target_link_libraries(${TEST_PROJECT_NAME} PRIVATE gtest_main gtest ${PROJECT_NAME})
gtest_discover_tests(${TEST_PROJECT_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE})
Expand Down
63 changes: 0 additions & 63 deletions sdk/tests/ECDSAsecp256k1PrivateKeyTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,66 +131,3 @@ TEST_F(ECDSAsecp256k1PrivateKeyTest, Derive)
EXPECT_THROW(auto key = getTestPrivateKeyLoaded()->derive(0), UninitializedException);
EXPECT_THROW(auto key = getTestPrivateKeyGenerated()->derive(0), UninitializedException);
}

//-----
TEST_F(ECDSAsecp256k1PrivateKeyTest, SLIP10TestVector1)
{
// SLIP10 spec provided test vector
std::string hexSeed = "000102030405060708090a0b0c0d0e0f";

std::unique_ptr<ECDSAsecp256k1PrivateKey> privateKey =
ECDSAsecp256k1PrivateKey::fromSeed(internal::HexConverter::hexToBase64(hexSeed));

std::string expectedChainCode = "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508";
std::string expectedPrivate = "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35";
std::string expectedPublic = "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(internal::DerivationPathUtils::getHardenedIndex(0));
expectedChainCode = "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141";
expectedPrivate = "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea";
expectedPublic = "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(1);
expectedChainCode = "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19";
expectedPrivate = "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368";
expectedPublic = "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(internal::DerivationPathUtils::getHardenedIndex(2));
expectedChainCode = "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f";
expectedPrivate = "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca";
expectedPublic = "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2);
expectedChainCode = "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd";
expectedPrivate = "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4";
expectedPublic = "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(1000000000);
expectedChainCode = "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e";
expectedPrivate = "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8";
expectedPublic = "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011";

EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));
}
111 changes: 0 additions & 111 deletions sdk/tests/ED25519PrivateKeyTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,114 +140,3 @@ TEST_F(ED25519PrivateKeyTest, Derive)
// Throw if input index is hardened
EXPECT_THROW(privateKey = privateKey->derive(1 | 0x80000000), std::invalid_argument);
}

TEST_F(ED25519PrivateKeyTest, SLIP10TestVector1)
{
// SLIP10 spec provided test vector
const std::string hexSeed = "000102030405060708090a0b0c0d0e0f";

std::unique_ptr<ED25519PrivateKey> privateKey =
ED25519PrivateKey::fromSeed(internal::HexConverter::hexToBase64(hexSeed));
std::string expectedChainCode = "90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb";
std::string expectedPrivate = "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7";
std::string expectedPublic = "a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(0);
expectedChainCode = "8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69";
expectedPrivate = "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3";
expectedPublic = "8c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(1);
expectedChainCode = "a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14";
expectedPrivate = "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2";
expectedPublic = "1932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2);
expectedChainCode = "2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c";
expectedPrivate = "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9";
expectedPublic = "ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2);
expectedChainCode = "8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc";
expectedPrivate = "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662";
expectedPublic = "8abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(1000000000);
expectedChainCode = "68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230";
expectedPrivate = "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793";
expectedPublic = "3c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));
}

TEST_F(ED25519PrivateKeyTest, SLIP10TestVector2)
{
// SLIP10 spec provided test vector
const std::string hexSeed = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e"
"7b7875726f6c696663605d5a5754514e4b484542";

std::unique_ptr<ED25519PrivateKey> privateKey =
ED25519PrivateKey::fromSeed(internal::HexConverter::hexToBase64(hexSeed));
std::string expectedChainCode = "ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b";
std::string expectedPrivate = "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012";
std::string expectedPublic = "8fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(0);
expectedChainCode = "0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d";
expectedPrivate = "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635";
expectedPublic = "86fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2147483647);
expectedChainCode = "138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f";
expectedPrivate = "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4";
expectedPublic = "5ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(1);
expectedChainCode = "73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90";
expectedPrivate = "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c";
expectedPublic = "2e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2147483646);
expectedChainCode = "0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a";
expectedPrivate = "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72";
expectedPublic = "e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));

privateKey = privateKey->derive(2);
expectedChainCode = "5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4";
expectedPrivate = "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d";
expectedPublic = "47150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0";
EXPECT_EQ(privateKey->getChainCode(), internal::HexConverter::hexToBase64(expectedChainCode));
EXPECT_EQ(privateKey->toBytes(), internal::HexConverter::hexToBase64(expectedPrivate));
EXPECT_EQ(privateKey->getPublicKey()->toBytes(), internal::HexConverter::hexToBase64(expectedPublic));
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@

using namespace Hedera;

// test vectors all have the same passphrase
const static std::string PASSPHRASE = "TREZOR";

class MnemonicBIP39TestVectors : public testing::TestWithParam<std::tuple<std::string, std::string, std::string>>
class BIP39TestVectors : public testing::TestWithParam<std::tuple<std::string, std::string, std::string>>
{
protected:
[[nodiscard]] inline const std::string& getPassphrase() const { return mPassphrase; }

private:
// BIP39 spec provided passphrase
const std::string mPassphrase = "TREZOR";
};

//-----
TEST_P(MnemonicBIP39TestVectors, TestVectors)
TEST_P(BIP39TestVectors, TestVectors)
{
const auto& [inputEntropy, mnemonicString, seed] = GetParam();

Expand All @@ -43,13 +46,13 @@ TEST_P(MnemonicBIP39TestVectors, TestVectors)
MnemonicBIP39 mnemonicFromString = MnemonicBIP39::initializeBIP39Mnemonic(mnemonicString);

ASSERT_EQ(mnemonicFromEntropy.toString(), mnemonicFromString.toString());
ASSERT_EQ(mnemonicFromEntropy.toSeed(PASSPHRASE), internal::HexConverter::hexToBase64(seed));
ASSERT_EQ(mnemonicFromEntropy.toSeed(getPassphrase()), internal::HexConverter::hexToBase64(seed));
}

//-----
INSTANTIATE_TEST_SUITE_P(
MnemonicBIP39,
BIP39TestVectors,
MnemonicBIP39TestVectors,
::testing::Values(
std::make_tuple("00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
Expand Down
Loading

0 comments on commit 5f4154b

Please sign in to comment.