-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ledger Nano S #3303
Ledger Nano S #3303
Conversation
Referencing #3095 if anyone is interested in previous discussion. |
Is this production tested and ready for general use? |
unit_tests should not crash if a device is not connected.
|
src/device/CMakeLists.txt
Outdated
target_link_libraries(device | ||
PUBLIC | ||
pcsclite | ||
crypto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crypto
${OPENSSL_CRYPTO_LIBRARIES}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added for next commit
@iDunk5400 strange, test should use the default device. Not NanoS one. I check that. Edited:
And it does'nt crash, and do not attemp any access to the device "ledger" |
src/crypto/crypto.cpp
Outdated
void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::Device &device) { | ||
device.derivation_to_scalar(derivation, output_index, res); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could all those be in a device file ? Or at least grouped together. Not a big thing though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
created a crypto_device.cpp.
src/crypto/crypto.cpp
Outdated
|
||
void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { | ||
struct { | ||
key_derivation derivation; | ||
crypto::key_derivation derivation; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add this upon complier claimed it did not know the symbol else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src/crypto/crypto.cpp
Outdated
|
||
bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index, | ||
const public_key &base, public_key &derived_key) { | ||
ec_scalar scalar; | ||
crypto::ec_scalar scalar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same thing, will try to remove that tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src/crypto/crypto.cpp
Outdated
|
||
void crypto_ops::derive_secret_key(const key_derivation &derivation, size_t output_index, | ||
const secret_key &base, secret_key &derived_key) { | ||
ec_scalar scalar; | ||
crypto::ec_scalar scalar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src/crypto/crypto.cpp
Outdated
assert(sc_check(&base) == 0); | ||
derivation_to_scalar(derivation, output_index, scalar); | ||
sc_add(&derived_key, &base, &scalar); | ||
hw::ledger::log_hexbuffer("crypto_ops::derive_secret_key: OUT : base", derived_key.data, 32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be in a non-device function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, I miss it! Even after reading the diff twice :(
Sorry will be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src/wallet/wallet2.cpp
Outdated
} | ||
device.set_signature_mode(device.SIGNATURE_FAKE); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Urgh. What is the purpose of these extra calls ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-reading, not needed. Related to previous thoughts.
Removed
tests/crypto/CMakeLists.txt
Outdated
blockchain_db | ||
p2p | ||
epee | ||
device |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
o_O Surely this is not needed, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linker make me crazy about think found or not. YES I need help on this point. Could someone check and try to clean the dependencies?
@@ -33,7 +33,7 @@ | |||
#include "crypto-tests.h" | |||
|
|||
bool check_scalar(const crypto::ec_scalar &scalar) { | |||
return crypto::sc_check(crypto::operator &(scalar)) == 0; | |||
return sc_check(crypto::operator &(scalar)) == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because of:
/home/cme/Projects/Git/Monero/monero-cslashm/tests/crypto/crypto.cpp:36:18: error: ‘sc_check’ is not a member of ‘crypto’
return crypto::sc_check(crypto::operator &(scalar)) == 0;
Moreover sc_check is defined in src/crypto/crypto-ops.c outside any namspace. So I dont understand this crypto::
Do I miss something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it was compiling fine before, no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I do not remember as I had dis-activated test compilation for a long period.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That needs to be worked out. It should not be needed unless something broke.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see below
crypto::ge_tobytes(crypto::operator &(res), &point); | ||
ge_p2 point; | ||
ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h)); | ||
ge_tobytes(crypto::operator &(res), &point); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, something broke and needs fixing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I think I found and I'm right.
in src/crypto/crypto.cpp we have
namespace crypto {
using std::abort;
using std::int32_t;
using std::int64_t;
using std::size_t;
using std::uint32_t;
using std::uint64_t;
extern "C" {
#include "crypto-ops.h"
#include "random.h"
}
....
The file test/crypto/crypto.cpp directly includes src/crypto/crypto.cpp (which a bit "ugly" I think).
This inclusion seems to temporarily move crypto-ops definition to crypto namespace
In my PR "crypto-ops.h" is incuded earlier pushing the definitions out of any namespace, as it should
according to namespace-less definition to crypto-ops.c/crypto-ops.h .
In conclusion I think this modifications should be keep.
(I also clean up my includes modification in the upcoming push update)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does crypto.h now include crypto-ops.h ? Is it really needed ? You seem to add just new prototypes, so th enew include doesn't seem needed at first glance, and it's apparently causing this namepace change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new/moved API use ge_p3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've waded through this code, and I see now how it is. I'm fine with those changes.
crypto::hash_to_ec(key, tmp); | ||
crypto::ge_p3_tobytes(crypto::operator &(res), &tmp); | ||
ge_p3_tobytes(crypto::operator &(res), &tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why all the namespace changes ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above
@cslashm to save you guys the hassle of having to rebase we've temporarily paused merging PRs, do you think you'll be able to do the last few tweaks to this on Monday? That way we don't leave things frozen for too long:) |
Ok I will work on Monero all the day on Monday. Thanks for nice collaboration.
Le 24 févr. 2018 16:05, "Riccardo Spagni" <notifications@github.com> a
écrit :
… @cslashm <https://github.com/cslashm> to save you guys the hassle of
having to rebase we've temporarily paused merging PRs, do you think you'll
be able to do the last few tweaks to this on Monday? That way we don't
leave things frozen for too long:)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3303 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFOX8zNxIzycIkUoH4zmeuK1Jyv8Xbafks5tYCVEgaJpZM4SOGTT>
.
|
src/device/device.cpp
Outdated
|
||
namespace { | ||
static std::map<std::string, Device&> registry; | ||
static int inited = []() -> int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this into a function please. This is ripe for initialization order fiasco issues ... You'd have to move everything into a struct that has a single instance created in static memory, because otherwise the creation algorithm is racy between the two elements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean you want I use a function call in main let's device_init() from main and totally discard the use of static lambda construction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I move the code in a hw::device_init() function. And I call this func from all main() functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's "on_startup" in src/common/util.cpp for these things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not solve the problem I was referencing. In C++, statics are initialized before main. If another constructor tries to ask for the device, and an object of that type is created in static memory, undefined behavior results. The only way to fix this specific problem is to do:
device& get_device(const std::string& name) {
struct devices {
devices() : device_map() { ... init... };
std::map<std::string, std::unique_ptr<device> device_map;
};
static const devices instance;
return instance.device_map.at(name);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should note that no constructor is calling this before main. But its easy to add this and add hard to spot undefined behavior.
src/ringct/rctOps.h
Outdated
@@ -112,10 +112,14 @@ namespace rct { | |||
|
|||
//does a * G where a is a scalar and G is the curve basepoint | |||
void scalarmultBase(key & aG, const key &a); | |||
void scalarmultBase(key & aG, const key &a, hw::Device &device); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are these redirects useful? Why wouldn't the places using them just call the function on the device directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see other comment (Moneromooo request + device routing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other responses about this topic
src/ringct/rctOps_device.cpp
Outdated
|
||
key scalarmultBase(const key & a, hw::Device &device) { | ||
key aG; | ||
device.scalarmultBase(aG, a); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't this function just return this value? Why the out parameter argument here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compute aG = a.G, as non device function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't the virtual method return the value like this function does?
src/crypto/crypto_device.cpp
Outdated
} | ||
|
||
secret_key generate_keys(public_key &pub, secret_key &sec, hw::Device &device) { | ||
secret_key rng; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mentioned this below, why these redirect functions? Why not just call the function directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the following reasons:
- Upon @moneromooo-monero request who do not want modification in original low crypto functions
- to manage the device abstraction between the various device implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So wait, is the only reason to "blind" the device type in the function call? I.e. the header for the type does not have to be included in some other library, and instead forwards to here? There has to be a better arrangement for this ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are equivalent to the following ones defined in crypto.h/cpp and using underlaying device
static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
src/crypto/crypto_device.cpp
Outdated
|
||
secret_key generate_keys(public_key &pub, secret_key &sec, hw::Device &device) { | ||
secret_key rng; | ||
device.generate_keys(pub, sec, secret_key(), false, rng); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the device returning secret keys? Is this the view key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secret key are returned AES encrypted as said in PR comment. View/Spend key are never returned, even encrypted. As reminder:
The basic approach it to delegate all sensitive data (master key, secret ephemeral key,
key derivation, ....) and related operations to the device. As the device as low
memory the device do not keep itself the values (except for view/spend keys) but once
computed there are encrypted (AES) and return back to monero-wallet-cli. When
they need to be manipulated by the device, they are decrypted on receive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets starts with this - why are there two secrets keys here? What is being generated and returned by this call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as said:
There are equivalent to the following ones defined in crypto.h/cpp and using underlaying device
static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
src/device/device_default.hpp
Outdated
#ifdef DEBUGLEDGER | ||
//bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey); | ||
#endif | ||
bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theres lots to add in here, but add in the override
tag to all of thee virtual
functions so the compiler errors out if the base class interface changes. It will do this if the base class functions are pure virtual (because a definition is required), but otherwise this keyword helps subtle issues with interface changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
override added everywhere in device_default and device_ledger
src/device/device_default.hpp
Outdated
DeviceDefault(const DeviceDefault &device); | ||
~DeviceDefault(); | ||
|
||
DeviceDefault& operator=(const DeviceDefault &device); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the opposite, mark this as deleted: DeviceDefault& operator=(DeviceDefault const&) = delete;
. The name of this class also breaks with existing style, but I guess @moneromooo-monero hasn't been concerned ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renaming done, a bit boring but done:
- Device=>device
- DeviceDefault => device_default
- DeviceLedger => device_ledger
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, If correctly understand I should mark all assignment copy as deleted to avoid their usage
Let me test that and think about it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/device/device_default.hpp
Outdated
class DeviceDefault : public hw::Device { | ||
public: | ||
DeviceDefault(); | ||
DeviceDefault(const DeviceDefault &device); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mark as deleted, this time with DeviceDelete(DeviceDelete const&) = delete;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/device/device_ledger.cpp
Outdated
MDEBUG( "Device "<<this->id <<" Created"); | ||
} | ||
|
||
DeviceLedger::DeviceLedger(const DeviceLedger &device): DeviceLedger() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the copy construtor and assignment ever used? I would just delete them, because its unlikely to be in use with this specific implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rereading all, yes copy/assignment constructors are no more used. I removed all of them by marking them
=delete
src/device/device_ledger.cpp
Outdated
MDEBUG( "Device "<<this->id << " LOCKed"); | ||
} | ||
void DeviceLedger::unlock_device() { | ||
MDEBUG( "Ask for UNLOCKING for device "<<this->id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't do this. It can throw, and leave the device locked. Best case this would have to be wrapped in its own try/catch block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure to understand what you suggest. MDEBUG may throw exception?
So I modified with:
try {
MDEBUG( "Ask for UNLOCKING for device "<<this->id);
} catch (...) {
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes MDEBUG
can throw in many different locations internally (it allocates memory, even if debug logging if off) .... yes I know.
src/wallet/wallet2.cpp
Outdated
@@ -1090,7 +1070,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote | |||
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) | |||
{ | |||
additional_derivations.push_back({}); | |||
if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back())) | |||
if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(),device)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate by one space, please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
U+1F612
src/wallet/wallet2.cpp
Outdated
for (size_t n = 0; n < tx.vout.size(); ++n) | ||
{ | ||
const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target)); | ||
if (!out_key) | ||
continue; | ||
|
||
crypto::public_key derived_out_key; | ||
bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key); | ||
bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key,device); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spacing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
U+1F612
src/wallet/wallet2.h
Outdated
@@ -486,6 +486,11 @@ namespace tools | |||
void generate(const std::string& wallet, const epee::wipeable_string& password, | |||
const cryptonote::account_public_address &account_public_address, | |||
const crypto::secret_key& viewkey = crypto::secret_key()); | |||
/*! | |||
* | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please complete the commentary, or remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
U+1F612
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. I was trying to help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is right, though. This is pointless AFAICT :P
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); | ||
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; | ||
crypto::cn_slow_hash(data, size, pwd_hash.data()); | ||
crypto::cn_slow_hash_pre(data, size, pwd_hash.data(), prehashed); | ||
memcpy(&key, pwd_hash.data(), sizeof(key)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be clearer to have a separate generate_chacha_key_prehashed, and leave the current code untouched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this breaks builds for arm & x86 as cn_slow_hash_pre()
exists only for
#if !defined NO_AES && (defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64)))
//----------------------------------------------------------------- | ||
hw::device& account_keys::get_device() const { | ||
return *m_device; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you try having a const/const and a non-const/non-const as suggested ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. Whatever the way i choose it implies too many modification. I really would like postpone this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll look at it once it's merged.
src/cryptonote_basic/account.cpp
Outdated
void account_base::create_from_device(const std::string &device_name) | ||
{ | ||
|
||
hw::device &hwdev = hw::get_device("ledger");// m_keys.get_device(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"ledger" should not be in the lib. If this is the device_name, use it. Otherwise, pass another parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me see that, yes maybe here a rest of the first integration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, You are right.
src/cryptonote_basic/account.cpp
Outdated
hwdev.init(); | ||
hwdev.connect(); | ||
hwdev.get_public_address(m_keys.m_account_address); | ||
#ifdef DEBUGLEDGER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick mass sed to DEBUG_HWDEVICE ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
crypto::secret_key m; | ||
hwdev.get_subaddress_secret_key(a, index, m); | ||
return m; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same opinion as vtnerd, it would be better to keep the same prototype, just with an extra device parameter. But at this point I'm OK with leaving those if it's too much hassle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will see. The waythe various subaddress functions are used and mixed make keeping the double prototype a bit hard and maybe dangerous. Need to think calmly about this.
src/device/CMakeLists.txt
Outdated
|
||
target_link_libraries(device | ||
PUBLIC | ||
pcsclite |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still doesn't look optional to me.
char dd[32]; | ||
char logstr[128]; | ||
|
||
memmove(dd,d,len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not see the bounds checks though. Like if (len < 0 || len >= sizeof(dd)) do_something_errory();
@@ -33,7 +33,7 @@ | |||
#include "crypto-tests.h" | |||
|
|||
bool check_scalar(const crypto::ec_scalar &scalar) { | |||
return crypto::sc_check(crypto::operator &(scalar)) == 0; | |||
return sc_check(crypto::operator &(scalar)) == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That needs to be worked out. It should not be needed unless something broke.
crypto::ge_tobytes(crypto::operator &(res), &point); | ||
ge_p2 point; | ||
ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h)); | ||
ge_tobytes(crypto::operator &(res), &point); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, something broke and needs fixing.
crypto::hash_to_ec(key, tmp); | ||
crypto::ge_p3_tobytes(crypto::operator &(res), &tmp); | ||
ge_p3_tobytes(crypto::operator &(res), &tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too.
Thanks
Le 27 févr. 2018 11:55, "moneromooo-monero" <notifications@github.com> a
écrit :
… ***@***.**** commented on this pull request.
------------------------------
In src/cryptonote_basic/account.cpp
<#3303 (comment)>
:
> @@ -50,6 +51,17 @@ DISABLE_VS_WARNINGS(4244 4345)
namespace cryptonote
{
+
+ //-----------------------------------------------------------------
+ hw::device& account_keys::get_device() const {
+ return *m_device;
+ }
OK, I'll look at it once it's merged.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3303 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFOX8xo-jIL5hIuWXbO2EMf5ckXjCAhPks5tY983gaJpZM4SOGTT>
.
|
src/device/device.cpp
Outdated
/* SETUP */ | ||
/* ======================================================================= */ | ||
|
||
static std::map<std::string, device&> registry; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be std::unique_ptr<device>
not device&
. Otherwise we are constantly going to get memcheck complaints about this.
src/ringct/rctSigs.cpp
Outdated
toHash[3 * i + 2] = aG[i]; | ||
toHash[3 * i + 3] = aHP[i]; | ||
rv.II[i] = scalarmultKey(Hi, xx[i]); | ||
} | ||
} | ||
precomp(Ip[i].k, rv.II[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to avoid breaking indent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall. Only minor comments.
src/crypto/slow-hash.c
Outdated
@@ -515,8 +515,11 @@ void slow_hash_free_state(void) | |||
* @param length the length in bytes of the data | |||
* @param hash a pointer to a buffer in which the final 256 bit hash will be stored | |||
*/ | |||
void cn_slow_hash(const void *data, size_t length, char *hash) { | |||
cn_slow_hash_pre(data,length,hash,0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use false instead of 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/device/device_default.hpp
Outdated
device_default(const device_default &device) = delete; | ||
device_default& operator=(const device_default &device) = delete; | ||
|
||
explicit operator bool() const { return false; }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
override
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/device/device_ledger.hpp
Outdated
|
||
class Keymap { | ||
public: | ||
std::vector<struct ABPkeys> ABP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use class
to avoid a warning (or define ABPkeys
as struct
, or just write std::vector<ABPkeys>
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course! Dont know why struct
...
done
src/device/device_ledger.cpp
Outdated
this->buffer_send[offset] = 0x00; | ||
offset += 1; | ||
//index | ||
static_assert(sizeof(cryptonote::subaddress_index) == 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static_assert
needs a second parameter which is a string describing the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/device/device_ledger.cpp
Outdated
this->buffer_send[offset] = 0x00; | ||
offset += 1; | ||
//index | ||
static_assert(sizeof(cryptonote::subaddress_index) == 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/simplewallet/simplewallet.cpp
Outdated
return print_seed(false); | ||
} | ||
|
||
bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/) | ||
{ | ||
if (m_wallet->key_on_device()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test can be inserted to print_seed
instead to take effect for both seed
and encrypted_seed
at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added to print_seed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant not only adding to print_seed
, but also removing it from seed
and encrypted_seed
because they both call print_seed
internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, removed
src/wallet/wallet2.cpp
Outdated
test_tx, | ||
test_ptx); | ||
} | ||
hwdev.set_signature_mode(hwdev.SIGNATURE_FAKE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hw::device::SIGNATURE_FAKE
to explicitly tell that it's a static const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/wallet/wallet2.cpp
Outdated
} | ||
hwdev.set_signature_mode(hwdev.SIGNATURE_FAKE); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the same code needs to be added to create_transactions_from
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me see that in detail; who call it ...
Maybe I should reject this command/function today
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's needed for the sweep_all, sweep_below, sweep_single
commands. You can add the same code to create_transactions_from
just like you did to create_transactions_2
. Very simple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/wallet/wallet2.cpp
Outdated
@@ -6819,6 +6850,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp | |||
unsigned int original_output_index = 0; | |||
std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second; | |||
std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; | |||
hw::device &hwdev = m_account.get_device(); | |||
hwdev.set_signature_mode(hwdev.SIGNATURE_FAKE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hw::device::SIGNATURE_FAKE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/wallet/wallet2.cpp
Outdated
if ((!dsts.empty()) || | ||
(dsts.empty() && !(adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) ) | ||
) { | ||
hwdev.set_signature_mode(hwdev.SIGNATURE_REAL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hw::device::SIGNATURE_REAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Please don't forget to address this simple compile error:
|
src/simplewallet/simplewallet.cpp
Outdated
fail_msg_writer() << tr("command not supported by HW wallet"); | ||
return true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to delete this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, removed
Please consider applying the following patch: diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt
index cdb35d2a..26389220 100644
--- a/src/device/CMakeLists.txt
+++ b/src/device/CMakeLists.txt
@@ -67,7 +67,7 @@ monero_add_library(device
target_link_libraries(device
PUBLIC
${PCSC_LIBRARIES}
- crypto
+ cncrypto
ringct
${OPENSSL_CRYPTO_LIBRARIES}
${GNU_READLINE_LIBRARY}
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index d22ea5f7..58496f93 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -329,8 +329,15 @@ namespace hw {
this->disconnect();
+#ifdef SCARD_AUTOALLOCATE
dwReaders = SCARD_AUTOALLOCATE;
- if ((rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders)) == SCARD_S_SUCCESS) {
+#else
+ rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders);
+ if (rv != SCARD_S_SUCCESS)
+ return false;
+ mszReaders = (LPSTR)calloc(dwReaders, sizeof(char));
+#endif
+ if ((rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders)) == SCARD_S_SUCCESS) {
char* p;
const char* prefix = this->name.c_str();
@@ -360,7 +367,11 @@ namespace hw {
}
if (mszReaders) {
+#ifdef SCARD_AUTOALLOCATE
SCardFreeMemory(this->hContext, mszReaders);
+#else
+ free(mszReaders);
+#endif
mszReaders = NULL;
}
if (rv != SCARD_S_SUCCESS) {
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index e6009517..02deee0c 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -3187,12 +3187,6 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
return true;
}
- if (m_wallet->key_on_device())
- {
- fail_msg_writer() << tr("command not supported by HW wallet");
- return true;
- }
-
COMMAND_RPC_STOP_MINING::request req;
COMMAND_RPC_STOP_MINING::response res;
bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client);
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index bb144227..9153eafc 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -151,7 +151,7 @@ bool WalletManagerImpl::walletExists(const std::string &path)
bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const
{
- return tools::wallet2::verify_password(keys_file_name, password, no_spend_key);
+ return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default"));
}
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) The only changes that may require a bit more care are those in ledger_device.cpp. The code was mostly copied from this tutorial site: https://ludovicrousseau.blogspot.jp/2010/04/pcsc-sample-in-c.html Actually, the code on the website looks a lot similar to yours; perhaps did you also use this site when writing the code? Anyway, I noticed an oddity in your code where you (an the site) wrote SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders) which is strange because |
@stoffu So I mod a bit your code proposition |
Please squash and fix the commit message and then it can go in. |
squashed |
The basic approach it to delegate all sensitive data (master key, secret ephemeral key, key derivation, ....) and related operations to the device. As device has low memory, it does not keep itself the values (except for view/spend keys) but once computed there are encrypted (with AES are equivalent) and return back to monero-wallet-cli. When they need to be manipulated by the device, they are decrypted on receive. Moreover, using the client for storing the value in encrypted form limits the modification in the client code. Those values are transfered from one C-structure to another one as previously. The code modification has been done with the wishes to be open to any other hardware wallet. To achieve that a C++ class hw::Device has been introduced. Two initial implementations are provided: the "default", which remaps all calls to initial Monero code, and the "Ledger", which delegates all calls to Ledger device.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed
e745c1e Code modifications to integrate Ledger HW device into monero-wallet-cli. (cslashm)
Will this support NANO S & Blue. I see there are references above to Blue which has more RAM |
When monero-project#3303 was merged, a cyclic dependency chain was generated: libdevice <- libcncrypto <- libringct <- libdevice This was because libdevice needs access to a set of basic crypto operations implemented in libringct such as scalarmultBase(), while libringct also needs access to abstracted crypto operations implemented in libdevice such as ecdhEncode(). To untangle this cyclic dependency chain, this patch splits libringct into libringct_basic and libringct, where the basic crypto ops previously in libringct are moved into libringct_basic. The cyclic dependency is now resolved thanks to this separation: libcncrypto <- libringct_basic <- libdevice <- libcryptonote_basic <- libringct This eliminates the need for crypto_device.cpp and rctOps_device.cpp. Also, many abstracted interfaces of hw::device such as encrypt_payment_id() and get_subaddress_secret_key() were previously implemented in libcryptonote_basic (cryptonote_format_utils.cpp) and were then called from hw::core::device_default, which is odd because libdevice is supposed to be independent of libcryptonote_basic. Therefore, those functions were moved to device_default.cpp.
When monero-project#3303 was merged, a cyclic dependency chain was generated: libdevice <- libcncrypto <- libringct <- libdevice This was because libdevice needs access to a set of basic crypto operations implemented in libringct such as scalarmultBase(), while libringct also needs access to abstracted crypto operations implemented in libdevice such as ecdhEncode(). To untangle this cyclic dependency chain, this patch splits libringct into libringct_basic and libringct, where the basic crypto ops previously in libringct are moved into libringct_basic. The cyclic dependency is now resolved thanks to this separation: libcncrypto <- libringct_basic <- libdevice <- libcryptonote_basic <- libringct This eliminates the need for crypto_device.cpp and rctOps_device.cpp. Also, many abstracted interfaces of hw::device such as encrypt_payment_id() and get_subaddress_secret_key() were previously implemented in libcryptonote_basic (cryptonote_format_utils.cpp) and were then called from hw::core::device_default, which is odd because libdevice is supposed to be independent of libcryptonote_basic. Therefore, those functions were moved to device_default.cpp.
4405e4f wallet2: check_tx_key() shouldn't require hardware encryption (stoffu) 7dfa5e9 chacha: call prehashed version explicitly as generate_chacha_key_prehashed hash: add prehashed version cn_slow_hash_prehashed slow-hash: let cn_slow_hash take 4th parameter for deciding prehashed or not slow-hash: add support for prehashed version for the other 3 platforms (stoffu) b2d23b1 crypto: revert odd namespace changes made in #3303 (stoffu) 8705bea keypair::generate: always require hw::device to avoid possible mistake (stoffu) 27a196b device: untangle cyclic depenency (stoffu) c9b38b4 device: made function prototypes consistent with pre-#3303 codebase (stoffu)
This a new push request for Hardware Wallet support in Monero client.
It replaces the push request #3095
Goals
The goal of this PR is to propose code modifications to integrate the ledger HW into
monero-wallet-cli.
Approach
The idea relies on 2 main principles:
The basic approach it to delegate all sensitive data (master key, secret ephemeral key,
key derivation, ....) and related operations to the device. As the device as low
memory the device do not keep itself the values (except for view/spend keys) but once
computed there are encrypted (AES) and return back to monero-wallet-cli. When
they need to be manipulated by the device, they are decrypted on receive.
Moreover using the client for storing the value in encrypted form limits the modification
in the client code. Those values are transfered from one C-structure to another one
as previously.
The code is modified at tow main levels:
. crypto operations, mainly crypto.cpp and cryptonote_format_utils.cpp
. signature level, mainly rctSigs.cpp and cryptonote_tx_utils.cpp
The pdf (https://github.com/LedgerHQ/blue-app-monero/blob/master/doc/developer/blue-app-monero.pdf) gives more details (but is a little be obsolete)
The application device is located at https://github.com/LedgerHQ/blue-app-monero.
Open Integration
The integration has been done with the wishes to be open to any other hardware wallet.
To achieve that a C++ class hw::Device has been introduce. All the Monero
client code has been modified to use this new interface.
Two initial implementation are provided:
Now any HW that provide a class Device implementation would be defacto
supported by the Monero client.
What works
The today code support sending and receiving moneroj. It support main and sub-address.
In the "soon" future, it will support proof of send, proof of reserve.
Then will come other stuffs.