-
-
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
M/N multisig support #4036
M/N multisig support #4036
Conversation
@moneromooo-monero @stoffu and @luigi1111 please review my 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.
A few minor comments. No idea whether the scheme does what it's said to do though, that'll require a luigi.
tools::fail_msg_writer() << genms::tr("Error finalizing multisig"); | ||
return false; | ||
} | ||
extra_info[n] = wallets[n]->exchange_multisig_keys(pwd_container->password(), pkeys, signers); |
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 remove the error handling ?
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 it throws in case of error
@@ -81,6 +81,43 @@ namespace cryptonote | |||
} | |||
} | |||
//----------------------------------------------------------------- | |||
std::vector<crypto::public_key> generate_multisig_derivations(const account_keys &keys, const std::vector<crypto::public_key> &derivations) |
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.
Badly named ? It uses derivations to create public keys.
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 sk * Pk = Pk
. I can rename it if you want
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 understand the 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.
It uses derivations from previous round to generate derivations for new one.
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 does not generate derivations though, but public keys. Maybe you call these public keys derivations in your scheme ? If so, it's just confusing :)
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 always thought about key derivations as functions spawning keys from another keys. In our case spawned key is public. Maybe I was wrong :) Do you want me to rename it?
@@ -138,4 +175,8 @@ namespace cryptonote | |||
return true; | |||
} | |||
//----------------------------------------------------------------- | |||
uint32_t multisig_rounds_required(uint32_t participants, uint32_t threshold) | |||
{ |
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 do with an assert that the numbers are valid (op doesn't get <= 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.
this case is checked before this function called. but i can just in case
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
@@ -887,7 +887,7 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args) | |||
{ | |||
success_msg_writer() << tr("Another step is needed"); | |||
success_msg_writer() << multisig_extra_info; | |||
success_msg_writer() << tr("Send this multisig info to all other participants, then use finalize_multisig <info1> [<info2>...] with others' multisig info"); | |||
success_msg_writer() << tr("Send this multisig info to all other participants, then use exchage_multisig_keys <info1> [<info2>...] with others' multisig info"); |
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.
exchange
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.
fixed, but github doesn't show it for some reason
return true; | ||
} else { | ||
uint32_t threshold, total; | ||
m_wallet->multisig(NULL, &threshold, &total); |
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 should probably check the return value for true (and ready being true 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.
I did the check at the first then decided it's redundant because we already have check the wallet is multisig above. Do you think we need to check it here again?
src/wallet/wallet2.cpp
Outdated
for (size_t i = 0; i < info.size(); ++i) | ||
{ | ||
THROW_WALLET_EXCEPTION_IF(!verify_multisig_info(info[i], secret_keys[i], public_keys[i]), | ||
error::wallet_internal_error, "Bad multisig info: " + info[i]); | ||
error::wallet_internal_error, "Bad multisig info: " + info[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.
spurious
src/wallet/wallet2.cpp
Outdated
@@ -3604,74 +3794,54 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, | |||
else | |||
{ | |||
THROW_WALLET_EXCEPTION_IF(public_keys[i] == local_pkey, error::wallet_internal_error, | |||
"Found local spend public key, but not local view secret key - something very weird"); | |||
"Found local spend public key, but not local view secret key - something very weird"); |
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 your editor munging these automatically ? Must be a setting to stop 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.
Yes, it's editor's fault. The project uses different identations and my IDE goes crazy about it
@@ -1916,6 +1916,31 @@ namespace wallet_rpc | |||
}; | |||
}; | |||
|
|||
struct COMMAND_RPC_EXCHANGE_MULTISIG_KEYS |
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.
Bump RPC version at the top
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
tests/core_tests/chaingen.h
Outdated
@@ -549,7 +549,7 @@ inline bool do_replay_file(const std::string& filename) | |||
std::vector<crypto::public_key> spend_public_keys; \ | |||
for (const auto &k: all_multisig_keys) \ | |||
spend_public_keys.push_back(k); \ | |||
crypto::public_key spend_pkey = cryptonote::generate_multisig_N1_N_spend_public_key(spend_public_keys); \ | |||
crypto::public_key spend_pkey = cryptonote::generate_multisig_M_N_spend_public_key(spend_public_keys); \ |
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.
Can you add some tests for the new threshold cases ?
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 can... But the problem is core tests don't use wallet or it's parts and I need to copy and paste some code into appropriate macro...
CHECK_AND_ASSERT_THROW_MES(!derivations.empty(), "empty pkeys"); | ||
bool ready = false; | ||
CHECK_AND_ASSERT_THROW_MES(multisig(&ready), "The wallet is not multisig"); | ||
CHECK_AND_ASSERT_THROW_MES(!ready, "Multisig wallet creation process has already been finished"); |
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.
Probably should be a sanity check for signers size here.
e7f7b44
to
a704527
Compare
I fixed part of comments, part of comments need to be discussed. I will add some core tests soon. |
@moneromooo-monero I added core tests for my functionality as promised. Please check it out. I also fixed some of comments, others need to be discussed further :) |
211e89d
to
7c419f5
Compare
@naughtyfox I was trying to find a (white)paper describing the M/N multisig scheme you implemented but I haven't found it. Can you pls link the paper with the scheme? Thanks! |
@ph4r05 unfortunately I couldn't find public multisig paper either. We discussed details about extending it to arbitrary M/N scheme in |
@naughtyfox Aaah I see. I think the write-up describing how exactly the multisig variants work (also with the M/N) would be very beneficial to the Monero community. Without following the IRC channels or "reverse-engineering" it from the source code it may be quite complicated to get an idea how multisig in Monero works. IMO, Having published documentation would help to increase the transparency and security of the Monero, so other security researches could assess the multisig scheme security (and to check whether implementation matches the desired scheme). Unfortunately, there is no MRL-xx document yet on the multisig topic, as far as I know. There is also a paper on eprint describing basic Monero transactions, but again without multisigs. |
This is true. Recently we tried to fill the gap and issued post on hackernoon about basics in monero multisignatures - https://hackernoon.com/monero-multisignatures-explained-46b247b098a7. And of course, it's about N/N and N-1/N schemes only. I'll write some doc about multisignatures and will try to cover keys exchange and partial key images topics. PS I almost forgot! @UkoeHB wrote the book about monero internals and there is unpublished chapter about multisignatures - https://github.com/UkoeHB/Monero-RCT-report/blob/master/multisig_chapter-1-0.pdf |
Surae's almost done with the multisig paper. |
View access for current draft: https://v2.overleaf.com/read/bfjfkdgnhgvh we'll be submitting it for publication soon so I'm not tremendously willing to include the more general case for this document.. but I can be persuaded, especially if someone has a clearish write-up to include! I can't look at it very soon but I agree that at least the more general M/N description should at least end up in the Zero to Monero document |
I made some kind of writing to explain in more human readable manner what's been done in this PR. Unfortunately, I don't have math-writing knack so I did it in google docs (again) in more or less free manner. You may check this out here - https://docs.google.com/document/d/1lo2oLyXP8O8g98FkNK9feUvZx98H6h9fgvBZn5-Qiwg/edit?usp=sharing |
Please rebase. |
Multisig paper submitted to IACR. Link incoming in a few days. |
e7f7b44
to
9990099
Compare
rebased |
Me and @b-g-goodell had a conversation about hashing multisig in the middle of key exchange rounds and why rounds differs as pointed in this discussion - #4036 (comment). I wrote the doc to clarify why it's needed - https://docs.google.com/document/d/1CGzdx8AeaDgWI3HZ1HpYQDtsPY1iirqGfOjvrMhlpss/edit?usp=sharing |
9990099
to
12c7e82
Compare
rebased |
12c7e82
to
869b7c1
Compare
* support in wallet2 * support in monero-wallet-cli * support in monero-wallet-rpc * support in wallet api * support in monero-gen-trusted-multisig * unit tests for multisig wallets creation
869b7c1
to
9acf42d
Compare
MINFO("Creating spend key..."); | ||
std::vector<crypto::secret_key> multisig_keys; | ||
rct::key spend_pkey, spend_skey; | ||
// In common multisig scheme there are 4 types of key exchange rounds: |
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.
Tried to explain how key exchange process goes
clearStatus(); | ||
checkMultisigWalletNotReady(m_wallet); | ||
|
||
return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info); |
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 I need to SCOPED_WALLET_UNLOCK();
here as simplewallet
does?
@moneromooo-monero @b-g-goodell I added some descriptive comments. Also added multisig unit tests for 2/4 and 2/5 schemes which is passed. Rewrote multisig wallets creation function in unit tests also to make it common and more simple (i'm ready to discuss it). I also have some questions about when I should use keys unlockers like |
You use SCOPED_WALLET_UNLOCK when you want the wallet keys to be unlocked till the end of the scope. You use LOCK_IDLE_SCOPE when you want to be the only one accessing wallet2 till the end of the scope. The former implies the latter. |
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
9acf42d Multisig M/N functionality core tests added (naughtyfox) 9f3963e Arbitrary M/N multisig schemes: * support in wallet2 * support in monero-wallet-cli * support in monero-wallet-rpc * support in wallet api * support in monero-gen-trusted-multisig * unit tests for multisig wallets creation (naughtyfox)
9acf42d Multisig M/N functionality core tests added (naughtyfox) 9f3963e Arbitrary M/N multisig schemes: * support in wallet2 * support in monero-wallet-cli * support in monero-wallet-rpc * support in wallet api * support in monero-gen-trusted-multisig * unit tests for multisig wallets creation (naughtyfox)
9acf42d Multisig M/N functionality core tests added (naughtyfox) 9f3963e Arbitrary M/N multisig schemes: * support in wallet2 * support in monero-wallet-cli * support in monero-wallet-rpc * support in wallet api * support in monero-gen-trusted-multisig * unit tests for multisig wallets creation (naughtyfox)
Extended multisignatures to schemes M/N.
I saved compatibility with previous API flow for multisig wallets creation. 2/4 wallets creation process looks as follows:
For classic
N-1/N
wallets instead ofexchange_multisig_keys
you may also usefinalize_multisig
command as you did before. Signing and submitting multisignature transactions procedure as well as partial key images exchange remain the same. In other words, onlyexchange_multisig_keys
was added from API perspective.Support for arbitrary scheme has been built also into:
monero-gen-trusted-multisig
utilityTwo members
m_multisig_rounds_passed
andm_multisig_derivations
have been added inwallet2
class to be able to continue creation procedure if the wallet has been closed between rounds.On of the first transactions sent from 2/4 wallet on stagenet is
244697a55e460e2188bb43b7a95ecf51298de1b6bc6a81f88d6d170e943ad0ef
, from 2/5 wallet -fd3bb0a12e44cdc4aa7834032c9ac15c7b0528c0bf9644d851e4d99d47606368
. I may provide these wallets if needed :)Tested with wallet api, wallet cli and wallet rpc on Ubuntu 17.10.
Core tests have also been added.