Skip to content
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

Merged
merged 2 commits into from
Oct 7, 2018
Merged

Conversation

naughtyfox
Copy link
Contributor

@naughtyfox naughtyfox commented Jun 21, 2018

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:

[wallet 5BUgPa]: prepare_multisig
Wallet password: 
MultisigV1XQAM98AQLYTAR83FDuGbn3Crvtgm9jRyKKEryVwcHC5j8sCaryT339hNBrbWXQUaEe4NUB7vv9BdPHTuZuUFvSoVbC273qbGrJGcAcDHbP91oXXd46xUVSzknRDQQ8L9ddjmZX789VveWRYUeyrP6Q5UVpEzmDn1NpfRA4NA21UxihEx
Send this multisig info to all other participants, then use make_multisig <threshold> <info1> [<info2>...] with others' multisig info
This includes the PRIVATE view key, so needs to be disclosed only to that multisig wallet's participants 

[wallet 5BUgPa]: make_multisig 2 MultisigV1A9TsWdMbPHtgvM6FDuYR7nPovfNdTPteSPFZwFgcNeR6PNsrmGjPvHbhiq7Ra1sMs9VrW5ev5MBX5aP1zTXmFLPcRcnj8i4zvoJ7qZS7YqyGdSgXfvwcoqS3bbtmASNmHivZNCyJkno5mdB1JNxD5wqUtNVUiQwRRfifTK6WFaNZjE2H MultisigV1hzHY9B7TuKaMF6cjjA53j4418G164HFzuVjtKGiam5YaVJm2rgTnXWZSHsQgPwW4abXpTS74SB8KbNs69DfzrsWB69ghrcRz3xuDUi4nnwEvxmAk8ECQQicbXiVfuWPyijdGUuiRHvnGBw6G3nXiWTYoKE5oLLgo7iGryFi68Vrp9MT2 MultisigV1SKvVDZ1ReJXMDbugtaJBiEEQ9hCVGD51we3b7w4pV5bPTCoigR7G2qoMQcaAgp87pXZCY9wDsHbRUHGwJYaGQ1NofLJJVP7they2rM348cpjEgAPVUoLxa52wjMP7pZQsfMeBCpZWKtiPL91J7R7uWes2DYH1gBRgpsHhFVjEeGrEDzx
Wallet password: 
Another step is needed
MultisigxV1jag57V1msEsWDDtYtTmaBCAR97maah4H2hxLeXfrXRWUEtNigxghaLA1ZjmjYiTyjYSXTucNMEeNvLBKtqrUME5ZNvtX3iiLLmJCzoXAMn2YhYDTUEpVi1bMN8fv3oxE9tQWNbghwVYazvjgBhXcRoNuh989GT84GEuDpjPcfSYDrosPeGj8KKH1AmsbQPCNoA7ppi6pSwjrzxJJW436KbKqHBwkAkhQVevWjj8Gmsbgg5ZQZcFRfFpMbJp8DXEtX32rKzEP
Send this multisig info to all other participants, then use exchage_multisig_keys <info1> [<info2>...] with others' multisig info

[wallet 51sLpF (out of sync)]: exchange_multisig_keys MultisigxV16oHHLiL2WsyEsmRj1fc37YJTmQs4bgmERBGRTKSoFxtR253qC31hnnTE7wy8xLFumwWmQzyAdjJjzR2cwfatJkpU6HX6WFSqE6DDsn5xyrPNiXifA6QCSfZxycnGA1roQ76p79BWRqr7yFzWUKu2uZYMDDYre85YEyZp5emiVz2JXeakQwARLCMk9neSSUsZFbPmPcMNmby9gQvScPgTXmKeBUKAjBK7njF6M1hGEkcKdPT2caiSYaX8V1mrZGpSxaESWDV9 MultisigxV1P5bu44mS6SqLWfh5f8AuNzDotbMT6iEf7LVaFfixJnyuM2VBNiwcJSbBbFifbgj7VidFZjzV1kpi64gRQk1aigGS6HX6WFSqE6DDsn5xyrPNiXifA6QCSfZxycnGA1roQ76pGSNmJhNYMSUNTdB2HviM6hFL2E9Uypy5eMjuQ9B4Wx4oBpXWmfjGbTk1qBUqPhyWwwU58jMqa9oQLSbv9TX8T82CYdFUEEgVVAvM1hoHjzpofLLxzPKFjyCofZ2UK3HsoLeq MultisigxV1BjP86fURDjY2L31oxTC64GDfDdPfqogahNdYLw2evHbo8PYmCtWxM8u7wSb6LY2VVrR4zW7vpq7QkGGkV2mYh19M79BWRqr7yFzWUKu2uZYMDDYre85YEyZp5emiVz2JXeakGSNmJhNYMSUNTdB2HviM6hFL2E9Uypy5eMjuQ9B4Wx4oE3351oRkZD86TH4z5SjThn2do9u6UXgDRExMNatSRcKVUCKFnmLLdCwdLYJATYMc2wFgq7rVG2LMdMX8jffrgVpC
Wallet password: 
Another step is needed
MultisigxV1AExg753mNvX17iyTbFX6Tq3sjpJ2YcPsgWi9jQkM2rMKctP8R5sBzZeCRDPXmCvHF54Gs7BKCj7W6AgPiwaLEJVF1r8MKR6yUmkeJMfexLhwun6VGqErFWFMV2SY1wXK5jNvFqLpiK3Ng6QjiWnAiqDccLajgFZvT5uLrXFgJm8JgrF5domBJYwSgZ89sfeC2RP45uQq6ksxGL3pYBThLwoWNieJS1A7P4MRqiiCYc2NqstSfzRVBeEZ3ezGhGNF89E2zL2YJos52A14AdFdF6PNUdK7UhMuGntMeBH8bgKAAuz1bfa57JDe4dwoC1rRTuhvL2Ewhq49PaQeBtntqHJuDnHwYme6cGkJGrEJoMqaX9tSajc1FkBgBop7hvkC6cq8BtMCjmZT
Send this multisig info to all other participants, then use exchange_multisig_keys <info1> [<info2>...] with others' multisig info

[wallet 51sLpF]: exchange_multisig_keys MultisigxV1PUq5CDZ9oWf3jUcWdx8aC32pWeCySeE7wJJH1aFaPVyAetYD2Bm9yh4PUSNuLtScvV2NKZzbQWQCgJq5saoLvCmVh5h5WtcM25Pc23k5ovZFjY8LnRjfT4DbkTCHv7kh2oPPRsW3Ax9XKFFEjRPh5DECjzCQMWwKXa9KneZmiQWB6kohV9nAHzG3ohYcHQq8E9NZR8UxsMDjRpmTxj6FrDPFCj2DXavpoe9reN94owQvP1dCc1XacHsVg7RKSKQMgUj8DNnS MultisigxV1dLf4xkCR7tD7C2cRhR1YATW5yJVFm2XiANVuMQjwsiM2etYD2Bm9yh4PUSNuLtScvV2NKZzbQWQCgJq5saoLvCmVd6syGgSUGA5hh8tkn8A6vpNhbwP5PjfBhfREypkSWuXjRsW3Ax9XKFFEjRPh5DECjzCQMWwKXa9KneZmiQWB6kohRuXSZGmcDNxYQoS5WSvC3P2qKQLTvLxULCDXUqbz6rJzA1st1tg4iRVdjdiWbyVPKRSBSU9oCx3wKKUkqhjqCGJR MultisigxV16FJqCGcFCnBTNTQmbY3CN7C5HqW62EMhXAh6Nax6rZ6UetYD2Bm9yh4PUSNuLtScvV2NKZzbQWQCgJq5saoLvCmVh5h5WtcM25Pc23k5ovZFjY8LnRjfT4DbkTCHv7kh2oPPd6syGgSUGA5hh8tkn8A6vpNhbwP5PjfBhfREypkSWuXj6tQM6LDnKbnJ8QkB9CePUK7q7wYM7x8JbJmj4D26Mko2DYAB5vbtmYjZxeapFTHuWYNgcgB4KAqoLFTb4M5Z9eGo
Wallet password: 
Multisig wallet has been successfully created. Current wallet type: 2/4
[wallet 526g4j]: address
0  526g4jUk2MxYjKFGrq655vAC9CBYLM66sWLn1VzXeAukE52fUbUkjsecpLLAzgBt7C9mTkutf29fnUEpPt39KUYZJ5votVx  Primary address 

For classic N-1/N wallets instead of exchange_multisig_keys you may also use finalize_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, only exchange_multisig_keys was added from API perspective.

Support for arbitrary scheme has been built also into:

  • wallet api
  • waller rpc
  • monero-gen-trusted-multisig utility

Two members m_multisig_rounds_passed and m_multisig_derivations have been added in wallet2 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.

@naughtyfox naughtyfox changed the title [WIP] M/N multisig support M/N multisig support Jul 12, 2018
@naughtyfox
Copy link
Contributor Author

@moneromooo-monero @stoffu and @luigi1111 please review my changes

Copy link
Collaborator

@moneromooo-monero moneromooo-monero left a 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);
Copy link
Collaborator

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 ?

Copy link
Contributor Author

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)
Copy link
Collaborator

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.

Copy link
Contributor Author

@naughtyfox naughtyfox Jul 13, 2018

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

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

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 :)

Copy link
Contributor Author

@naughtyfox naughtyfox Jul 17, 2018

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)
{
Copy link
Collaborator

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).

Copy link
Contributor Author

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -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");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exchange

Copy link
Contributor Author

@naughtyfox naughtyfox Jul 17, 2018

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);
Copy link
Collaborator

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)

Copy link
Contributor Author

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?

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]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spurious

@@ -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");
Copy link
Collaborator

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.

Copy link
Contributor Author

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
Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -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); \
Copy link
Collaborator

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 ?

Copy link
Contributor Author

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");
Copy link
Collaborator

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.

@naughtyfox naughtyfox force-pushed the multisig-mn branch 2 times, most recently from e7f7b44 to a704527 Compare July 13, 2018 15:43
@naughtyfox
Copy link
Contributor Author

naughtyfox commented Jul 13, 2018

I fixed part of comments, part of comments need to be discussed. I will add some core tests soon.

@naughtyfox
Copy link
Contributor Author

@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 :)

@naughtyfox naughtyfox force-pushed the multisig-mn branch 3 times, most recently from 211e89d to 7c419f5 Compare July 17, 2018 13:05
@ph4r05
Copy link
Contributor

ph4r05 commented Jul 24, 2018

@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!

@naughtyfox
Copy link
Contributor Author

@ph4r05 unfortunately I couldn't find public multisig paper either. We discussed details about extending it to arbitrary M/N scheme in #monero-research-lab IRC channel. The only part of my work here is to extend key exchange rounds to support M/N. This is enough to be integrated in partial key images exchange and MLSTAG signatures. I can do a write up to describe better what happens under the hood with wallet's keys. Would it be ok for you?

@ph4r05
Copy link
Contributor

ph4r05 commented Jul 24, 2018

@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 a description in the @moneromooo-monero commit message introducing the Multisigs moneromooo-monero@b99bd7eecf

There is also a paper on eprint describing basic Monero transactions, but again without multisigs.
https://eprint.iacr.org/2018/535

@naughtyfox
Copy link
Contributor Author

naughtyfox commented Jul 24, 2018

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

@moneromooo-monero
Copy link
Collaborator

Surae's almost done with the multisig paper.
You can ask him for a link to the current draft.

@b-g-goodell
Copy link

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

@naughtyfox
Copy link
Contributor Author

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

@moneromooo-monero
Copy link
Collaborator

Please rebase.

@b-g-goodell
Copy link

Multisig paper submitted to IACR. Link incoming in a few days.

@naughtyfox naughtyfox force-pushed the multisig-mn branch 2 times, most recently from e7f7b44 to 9990099 Compare August 28, 2018 10:03
@naughtyfox
Copy link
Contributor Author

rebased

@naughtyfox
Copy link
Contributor Author

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

@naughtyfox
Copy link
Contributor Author

rebased

* 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
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:
Copy link
Contributor Author

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);
Copy link
Contributor Author

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?

@naughtyfox
Copy link
Contributor Author

@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 SCOPED_WALLET_UNLOCK() in wallet api calls? It's kinda not transparent for me.

@moneromooo-monero
Copy link
Collaborator

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.

Copy link
Contributor

@fluffypony fluffypony left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed

@fluffypony fluffypony merged commit 9acf42d into monero-project:master Oct 7, 2018
fluffypony added a commit that referenced this pull request Oct 7, 2018
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)
fluffypony added a commit that referenced this pull request Oct 7, 2018
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)
fotolockr pushed a commit to fotolockr/monero that referenced this pull request May 1, 2019
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants