Skip to content

Commit 7406869

Browse files
committed
MUL-2: MVP for generating seed pharase, private/publick keys and addresses for BTC and ETH
C++ library with a C-style interface, tests and third-party dependencies as git subtrees. Features: BIP39 entropy to seed phrase and root key derivation. BIP44 account derivation. Bitcoin and Ethereum accounts as leafs of the same derivation tree, originating from single seed phrase. P2PKH addresses for Bitcoin accounts. Importing existing Bitcoin accounts in WIF. Importing existing Ethereum accounts.
1 parent 7ecace2 commit 7406869

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5547
-0
lines changed

CMakeLists.txt

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.1)
2+
3+
set(CMAKE_CXX_STANDARD 11)
4+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
5+
6+
option(WITH_TESTS "Build tests shared library (DLL)" NO)
7+
set(LIBWALLY_BIN "" CACHE FILEPATH "Path to prebuild libwally-core")
8+
set(LIBWALLY_BIN_PATH "" CACHE PATH "Path to directory with prebuild libwally-core")
9+
set(LIBSECP256K1_BIN "" CACHE FILEPATH "Path to prebuild libsecp256k1")
10+
set(LIBSECP256K1_BIN_PATH "" CACHE PATH "Path to directory with prebuild libsecp256k1")
11+
12+
project(multy)
13+
14+
add_executable(
15+
multy
16+
main.cpp
17+
)
18+
target_link_libraries(multy PRIVATE multy_core)
19+
target_include_directories(multy PRIVATE .)
20+
21+
add_subdirectory(multy_core)
22+
add_subdirectory(third-party)
23+
24+
if(WITH_TESTS)
25+
target_compile_definitions(multy PRIVATE WITH_TESTS)
26+
add_subdirectory(multy_test)
27+
target_link_libraries(multy PRIVATE multy_test)
28+
endif()
29+

CMakeLists.txt.user

+456
Large diffs are not rendered by default.

CODING_STYLE.md

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
First of all, use common scene.
2+
3+
Code has to be written for humans to read, do not overenginner nor overcomplicate.
4+
5+
## Exceptions
6+
All rules are soft enough to be lifted upon violation of common sense, but before breaking any rule, please discuss the case, since the rule itself might have an error on its own. Explicitly mark the exception with "CODING STYLE EXCEPTION" in comments.
7+
8+
Following does not apply to the code borrowed from other projects, like the dependencies in third-party.
9+
That is required to simplify merging when bumping version of dependency and\or updating the snippet.
10+
11+
## Formatting
12+
Use clang-format with enclosed clang-format.txt style on modified files before pushing them upstream.
13+
**Notice:** Sometime clang-format (as of version 3.8) produces very ugly results. In this case please don't just blindly commit your changes, but revert pieces that are utterly ugly. Notable examples are C++11 lambdas and array initializers.
14+
15+
## Global
16+
C++11, not C-with-classes.
17+
18+
Why C++11 but not 14, 17? This project aim is to be core of mobile app, and some target toolchains\SDKs do not support C++14 and above (in fact, even C++11 is not fully supported).
19+
20+
That means you are encouraged to use:
21+
22+
- STL
23+
- smart-pointers
24+
- exceptions
25+
- auto (with moderation)
26+
- GLSL (TODO)
27+
28+
## Interfaces
29+
We use C++11, however, due to ABI compatibility reasons and to simplify integration with other languages\platforms, core library has a C-like interface.
30+
That means:
31+
32+
- API functions should be ```extern "C"```
33+
- API functions take only primitive types and structs as argument, no C++ classes.
34+
- API functions throw no exceptions
35+
- Public headers do no include C++ headers (even standard ones).
36+
37+
General rules of thumb:
38+
39+
- API functions should have an explanation comment, stating function purpose, expectation on arguments values and promises on produced values.
40+
- If function is complicated enough, please put a comment at the very to, briefly describing what and why at the top-level.
41+
- All data\objects allocated within the library should be freed in the library.
42+
- Preferably a data\objects allocated\created in the translation unit, should be deallocated from that same unit.
43+
- Function arguments
44+
45+
## Naming
46+
47+
- All types, that is classes, structs, enums, typedefs are camel-case and begin with capital letter.
48+
- All functions use snake_case and NOT capitalized.
49+
- Function name should begin with verb.
50+
- Function that creates new object should have `make_` prefix, like `make_acount()`.
51+
- Variables (function parameters too) are all `snake_case` (all lower case), must be a noun.
52+
- Struct members follow rules for variables, and should have no prefixes.
53+
- Class members follow rules for variables, but also have a `m_` prefix.
54+
- Global constants and enum values, are `SNAKE_CASE`.
55+
56+
```
57+
class Foo
58+
{
59+
};
60+
61+
struct Bar
62+
{
63+
};
64+
65+
```
66+
67+
## Tests
68+
Write code with tests in mind, code which is not tested can't be really used. Please write tests even for trivial functions. However, do not test libc, OS, network and\or other external stuff, unless that is required specifically.
69+
We use gtest framework for unit-tests.
70+
Every library shipped should have a corresponding test library, where all unit-tests reside. That allows to ship test libraries to the target devices and verify correctness of the library. It is Ok to include in the test library specific tests for the dependencies of the shipped library.
71+
72+
## Dependencies
73+
We would like to minimizer library footprint and hence tend to minimize dependency, please do not bring you super-huge-and-cool-framewok if you need only a string-to-hex convertion function.
74+
Prefer C-libraries as dependencies over C++ counterparts, since those are generally more portable, easier to read and maintain.
75+
Right now we would like to avoid dependency on boost.

LICENSE

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Note: the modules in the third-party or tools directories have their own licenses, but except where noted in an individual source file, the rest of the code is covered by the following license:
2+
3+
Copyright 2017 Idealnaya rabota LLC (Republic of Belarus)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute (with limitations described below), sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
You shall not distribute in binary form any substantial portion of the Software if it has any modifications (in source code or assets) compared to original distribution from Idealnaya rabota LLC (Republic of Belarus) obtained from the official repository at https://github.com/Multy-io/ or https://github.com/Appscrunch.
8+
9+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10+
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

main.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* Copyright 2017 by Multy.io
2+
* Licensed under Multy.io license.
3+
*
4+
* See LICENSE for details
5+
*/
6+
7+
#include "multy_core/mnemonic.h"
8+
9+
#include "multy_core/common.h"
10+
#include "multy_core/error.h"
11+
#include "multy_core/internal/utility.h"
12+
13+
#include "multy_test/run_tests.h"
14+
15+
#include <iostream>
16+
#include <memory>
17+
#include <string.h>
18+
19+
namespace
20+
{
21+
22+
size_t entropySource(size_t size, void* dest)
23+
{
24+
/** Poor man's entropy, using uninitialized data from stack, which is:
25+
* - Fast;
26+
* - Unsecure;
27+
* - Somewhat predictable;
28+
* And hence SHOULD not be used in production, but Ok in POC driver program.
29+
*/
30+
static const size_t entropy_max_size = 1024;
31+
unsigned char silly_entropy[entropy_max_size];
32+
33+
if (size > entropy_max_size)
34+
{
35+
return 0;
36+
}
37+
38+
memcpy(dest, silly_entropy, size);
39+
return size;
40+
}
41+
42+
using namespace wallet_core::internal;
43+
44+
} // namespace
45+
46+
int main(int argc, char** argv)
47+
{
48+
#ifdef WITH_TESTS
49+
return run_tests(argc, argv);
50+
#else
51+
try
52+
{
53+
auto mnemonic = null_unique_ptr<const char>(free_mnemonic);
54+
throw_if_error(make_mnemonic(&entropySource, reset_sp(mnemonic)));
55+
std::cout << "Generated mnemonic: " << mnemonic.get() << std::endl;
56+
57+
std::cout << "Enter password: ";
58+
std::string password;
59+
std::getline(std::cin, password);
60+
61+
auto seed = null_unique_ptr<BinaryData>(free_binarydata);
62+
throw_if_error(
63+
make_seed(mnemonic.get(), password.c_str(), reset_sp(seed)));
64+
65+
auto seed_string = null_unique_ptr<const char>(free_string);
66+
throw_if_error(seed_to_string(seed.get(), reset_sp(seed_string)));
67+
std::cout << "Seed: " << seed_string.get() << std::endl;
68+
}
69+
catch (Error* e)
70+
{
71+
std::cerr << "Got error: " << e->message << std::endl;
72+
free_error(e);
73+
return -1;
74+
}
75+
return 0;
76+
#endif
77+
}

multy_core/CMakeLists.txt

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
set(CMAKE_CXX_STANDARD 11)
2+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
3+
4+
add_library(multy_core
5+
SHARED
6+
7+
src/account.cpp
8+
src/common.cpp
9+
src/error.cpp
10+
src/keys.cpp
11+
src/mnemonic.cpp
12+
13+
internal/account_base.cpp
14+
internal/account.cpp
15+
internal/bitcoin_account.cpp
16+
internal/ethereum_account.cpp
17+
internal/hd_path.cpp
18+
internal/key.cpp
19+
internal/u_ptr.cpp
20+
internal/utility.cpp
21+
)
22+
23+
target_compile_definitions(multy_core PRIVATE BUILDING_MULTY_CORE=1)
24+
target_include_directories(multy_core PRIVATE
25+
..
26+
../third-party/libwally-core/include/
27+
../third-party/libwally-core/src/ccan
28+
../third-party
29+
)
30+
31+
target_link_libraries(multy_core libwally-core keccak-tiny)
32+
set_target_properties(multy_core PROPERTIES CXX_VISIBILITY_PRESET hidden)
33+

multy_core/account.h

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* Copyright 2017 by Multy.io
2+
* Licensed under Multy.io license.
3+
*
4+
* See LICENSE for details
5+
*/
6+
7+
#ifndef MULTY_CORE_ACCOUNT_H
8+
#define MULTY_CORE_ACCOUNT_H
9+
10+
#include "multy_core/api.h"
11+
12+
#include <stddef.h>
13+
#include <stdint.h>
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
struct HDAccount;
20+
struct Account;
21+
struct Error;
22+
struct ExtendedKey;
23+
struct Key;
24+
25+
enum Currency
26+
{
27+
CURRENCY_BITCOIN,
28+
CURRENCY_ETHEREUM,
29+
};
30+
31+
enum AddressType
32+
{
33+
ADDRESS_EXTERNAL,
34+
ADDRESS_INTERNAL /** change-address **/
35+
};
36+
37+
enum KeyType
38+
{
39+
KEY_TYPE_PRIVATE,
40+
KEY_TYPE_PUBLIC,
41+
};
42+
43+
/** Make an account of given currency with given id.
44+
*
45+
* @param master_key - master key, generated from seed.
46+
* @param currency - currency to use account for.
47+
* @param index - acccount index
48+
* @param account - (out) new account
49+
*/
50+
MULTY_CORE_API struct Error* make_hd_account(
51+
const ExtendedKey* master_key,
52+
Currency currency,
53+
uint32_t index,
54+
struct HDAccount** new_account);
55+
56+
/** Make a leaf HD account - the one that has an address and can be paid from/to.
57+
* @param base_account - base account, for which leaf is generated.
58+
* @param address_type - type of address for account: internal or external.
59+
* @param index - index of account within base account.
60+
* @param new_account - newly created account, must be freed by caller with
61+
* free_account().
62+
*/
63+
MULTY_CORE_API struct Error* make_hd_leaf_account(
64+
const struct HDAccount* base_account,
65+
AddressType address_type,
66+
uint32_t index,
67+
struct Account** new_account);
68+
69+
/** Make regular account from private key and currency.
70+
* @param currency - currency to use account for.
71+
* @param serialized_private_key - private key for account.
72+
* @param new_account - newly created account, must be freed by caller with
73+
* free_account().
74+
*/
75+
MULTY_CORE_API struct Error* make_account(
76+
Currency currency,
77+
const char* serialized_private_key,
78+
struct Account** new_account);
79+
80+
/** Get a key from account.
81+
*
82+
* See keys.h for key manipulation API.
83+
* @param account - the account to get the key from.
84+
* @param key_type - either KEY_TYPE_PUBLIC or KEY_TYPE_PRIVTAE.
85+
* @param out_key - resulting key, must be freed by caller with free_key().
86+
*/
87+
MULTY_CORE_API struct Error* get_account_key(
88+
const struct Account* account,
89+
KeyType key_type,
90+
Key** out_key);
91+
92+
/** Get account address as a string.
93+
* @param account - account.
94+
* @param out_address - address string, must be feed by caller with free_string().
95+
*/
96+
MULTY_CORE_API struct Error* get_account_address_string(
97+
const struct Account* account,
98+
const char** out_address);
99+
100+
/** Get account HD path as a string.
101+
*
102+
* The path might be empty if account is not an HD-account, but an imported one.
103+
* @param account - account.
104+
* @param out_address_path - HD path string, must be feed by caller with free_string().
105+
*/
106+
MULTY_CORE_API struct Error* get_account_address_path(
107+
const struct Account* account,
108+
const char** out_address_path);
109+
110+
/** Get account currency.
111+
* @param account - account.
112+
* @param out_currency - where to store the currency value.
113+
*/
114+
MULTY_CORE_API struct Error* get_account_currency(
115+
const struct Account* account,
116+
Currency* out_currency);
117+
118+
/** Frees HDAccount instance, can accept nullptr. **/
119+
MULTY_CORE_API void free_hdaccount(struct HDAccount*);
120+
121+
/** Frees Account instance, can accept nullptr. **/
122+
MULTY_CORE_API void free_account(struct Account*);
123+
124+
#ifdef __cplusplus
125+
} /* extern "C" */
126+
#endif
127+
128+
#endif /* MULTY_CORE_ACCOUNT_H */

multy_core/api.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* Copyright 2017 by Multy.io
2+
* Licensed under Multy.io license.
3+
*
4+
* See LICENSE for details
5+
*/
6+
7+
#ifndef MULTY_CORE_API_H_INCLUDED
8+
#define MULTY_CORE_API_H_INCLUDED
9+
10+
#ifndef BUILDING_MULTY_CORE
11+
# define BUILDING_MULTY_CORE 0
12+
#endif
13+
14+
#if defined(_WIN32)
15+
# if (BUILDING_MULTY_CORE)
16+
# define MULTY_CORE_API __declspec(dllexport)
17+
# else
18+
# define MULTY_CORE_API
19+
# endif
20+
#elif defined(__GNUC__) && (BUILDING_MULTY_CORE)
21+
# define MULTY_CORE_API __attribute__ ((visibility ("default")))
22+
#else
23+
# define MULTY_CORE_API
24+
#endif
25+
26+
#endif // MULTY_CORE_API_H_INCLUDED

0 commit comments

Comments
 (0)