Hi! As discussed with @xuhcc, the signup and voting periods can overlap. If a user specified the wrong state index in a command, it’ll be a no-op when processed anyway.
xuhcc we need the cart to remain after submission until the end of the voting period to enable key-changing operations
Can we confirm final decision on this?
We should also indicate the voting period duration in the cart.
create a “contribution history” screen
We could add a tab in the Cart and list past contributions.
the user needs to be able to switch their signing keys and post a new batch of messages that invalidate the old messages
@auryn I think I need more clarity on how this process works and how this reflects on the front-end.
Does that effect the front-end in some way? Reading the original post from above I
don’t see any major changes in the user flow. What has been described by @auryn is mostly on the contract side. Is that correct?
This just means that the simpler of the two flows is possible.
Basically, along with their ethereum address, each user generates a set of eddsa keys which they use to sign their messages (vote commands). At any point, users can sign a message with their current eddsa key to update it to a new key, meaning that any future message sent with the old key is invalid. They can do this as many times as they like.
Yes, I think we should stick with the idea of items in the cart remaining after checkout.
Re-checking out should submit transactions to for any changes to the cart.
In theory, the items don’t need to be displayed explicitly in a cart structure after submission. For example, they could be displayed in some sort of “contributions this round” view, which could be simplified vs a full cart. As long as there’s a way to later recall the into the cart for key switching purposes.
That said, for the mvp it’s likely easier to just keep the cart format rather than designing and developing a new view.
If there is a way to sign up and publish messages in one call, the briber just demands the voter to use it and the voter has to obey if they want to receive the bribe. In that case, the voter submits two messages, one with the vote and another one that changes the key to an invalid key, and reveals them to the briber. The briber verifies messages and pays the bribe, knowing that the vote is valid and the voter can not override it later (because the new key is invalid). It doesn’t matter if there are other ways to publish messages.
I did some research on this topic and it seems that in order to prevent the vote-buying attack at the beginning of the voting period, two conditions must be satisfied:
- The first message must be a key-changing message and it must be submitted through the alternative channel like a trusted relayer (so there’s no trail on-chain that could be used to associate this message with the voter).
- It must be impossible to sign up and vote at the same time (to give the voter a chance to secretly submit a key-changing message).
Here’s how it might work:
- Users sign up.
- There is a period during which they can not vote (it can be relatively small).
- During that period voters may secretly give a key-changing message to the relayer/coordinator.
- At the end of this period relayer/coordinator publishes all collected messages.
- The voting begins.
Ah yeah, I see what you’re saying.
It seems the time delay between signup and voting is the crucial step as it allows time for key changes.
What do we think is the practical minimum for a time delay between signup and voting?
I don’t know that we need to force a key change, so long as there is a window of time where the voter could have changed their keys and the briber has no way to know whether or not they did.
One issue with this is there is no way for the smart contract to distinguish between a key-change message and a voting message.
That’s interesting.
But it could be enforced in MACI’s circuits though, no?
The goal of this period is to prevent voter from getting bribed immediately after the beginning of the voting period. Because in such case if voter reveals the voting message to the briber, the briber can verify that encrypted message has been included in the first block after the beginning of the voting period (even if it has been submitted by a relayer) and conclude that with high probablilty it is the first message, signed by a valid key.
Can the coordinator play the role of a trusted relayer? He can decrypt all relayed messages and publish only those that change the key.
That would only work if the relayer was the only person who could publish messages. In which case, the coordinator could censor votes, which I don’t believe they can do right now.
It seems to me we’ll need to provide users a way to submit messages through multiple addresses to avoid the briber simply requesting that all messages published from a certain address be decrypted by the bribee and uncovering all key change messages that way.
Not sure in which proof-of-concept round we’ll want to support this.
I understand now.
From user POW I found it really weird when donating on Gitcoin and then going back to my cart seeing the very same cart with the same amounts. I thought something went wrong and my contribution didn’t come through (although I got notified).
For this milestone we can keep the same cart view but I’d prepare and design a “contributions this round” view or “History” tab within the cart as we discussed earlier.
Users will submit only key-changing messages during this period of restricted access. Coordinator can’t censor votes, because during the voting period there will be no restrictions.
On the contracts level this will be supported from the very beginning.
Can the signup and vote period still overlap in this scenario?
In other words, can we build it such that this delay is enforced on an individual level, rather than globally?
Another thing I fear with this is that it increases the burden on the coordinator.
Rather than being a role that is required to perform a calculation and post the corresponding proof once per round, the coordinator would now require constant availability.
My thoughts on the coordinator relay idea is that it is interesting, and something like it may be necessary long-term, but it’s probably out of scope for PoC/MvP.
I don’t know. That would probably require significant changes to MACI.
Yes, I agree that we can accept some risk of bribing in PoC. I suggest this workflow:
- User calls
contribute()
and signs up. - A key-change message is created and UI tells the user that the message should be submitted through the alternative channel in order to fool the briber (but we don’t enforce it).
- User submits a key-change message by calling
MACI.publishMessage()
. - A batch of voting messages is created (signed with an old key in case of bribing, and with a new key otherwise).
- User submits the batch by calling
submitMessageBatch()
.
This would require 3 transactions, but would make vote-buying attack a little bit harder.
I’d suggest that our interface can still roll contribute
and submitMessageBatch()
into one transaction. Since the user can always update their key and invalidate the previous messages if need be.
I don’t think there is a meaningful difference in protection between this and your 3 transaction suggestion, but there is a meaningful UX impact.
This means that our interface needs to provide a way to generating and using a new signing key, along with instructions on how to send the MACI.publishMessage()
transaction from another unrelated address to enable the new signing key.
The difference is significant. As I described previously, if there’s a way to sign up and vote in one call, the vote-buying attack becomes very easy: the briber simply provides a specially-crafted transaction to the user and it’s done.
Right, but in your most recent suggestion they can still do that, just not in our interface.
Unless you’re suggesting that the contracts should or will have some protection against these things happening in the same transaction, I still don’t see a meaningful difference.
So we could do something like enforce a time/block limit between signup and publishing a message, which would mean that you can’t do both in one transaction. But then you just create a race condition where the briber just has to ensure that the vote transaction that they want gets in on the first block that it’s allowed, rather than your keychange transaction.
Actually, that’s an interesting issue. Since it wouldn’t be one or the other. How does MACI handle it if there is are multiple messages in a block like this:
- message A: vote for bribers project with key x
- message B: change to key y
Is message A valid?
If not, then I think what you’re suggesting would work @xuhcc.
They will need to create a special contract for that, and attempts to use it will be visible. As I said, the goal is to make the attack a little bit harder (while minimizing the amount of work required for PoC). Another reason for that is to design a workflow which will be compatible with the final implementation (probably the one with a period of restricted messaging, though I hope we’ll find a better solution).
Yes, it’s the simplest solution. This should be the reason why there are distinct signup and voting periods in MACI.
I think it depends on the order of transactions in a block (which could be hard to predict). If A comes before B, then it is valid.