0

I have the following use case. There's a smart contract based game where everyone can award 1 point to a color. At the end of the game, the smart contract reveals which color is the most popular/has gained the most points. Take the following Solidity code:

struct Color{
        string colorName;
        uint256 awardedPoints; 
        uint256 colorID;
    }

mapping(uint256 => Color) private colorsMapping;

function awardPoint(uint256 colorID) public {
        colorsMapping[colorID].awardedPoints++;    
    }

Of course, the mapping is marked with the "private" keyword, but that doesn't really stop determined people from revealing the content. Besides, everyone can count the calls for function awardPoint(colorID) and deduce partial results.

What would be the best way of solving this with minimal changes to the code?

What I thought about:

  1. Every time someone calls function awardPoint(colorID), colorIDs are randomly shuffled. However, they are tied to the mapping already, so I don't really see a wait of implementing this in Solidity. Besides, it wouldn't really solve the issue of someone revealing the data of the colorsMapping private variable.
  2. Adding random numbers to awardedPoints count every time someone calls awardpoint function, similar to weights. However, I have a hard time thinking about how to substract them later, how and where to store them etc.
  3. Homomorphic encryption: I'm not very familiar with the concept, but I know that you can perform operations on encrypted data (in this case incrementations) and you can decrypt the results at the end. However, I have no idea how to implement this in Solidity (or at all).

What approach would be the best?

1 Answer 1

1

One way to solve this is the commit and reveal strategy.

In the commit phase everyone will send to the contract a hash that was obtained from the color and a salt value.

function commitColor(bytes32 hash) public {
    commits[msg.sender] = hash;
}

In the reveal phase the color and salt are revealed

function reveal(unit256 color, bytes32 salt) public {
    bytes32 hash = keccak256(abi.encode(color, salt));
    require(commits[msg.sender] == hash, "Invalid hash");

    colorsMapping[colorID].awardedPoints++;  
}

That's the basic idea. Obviously this introduces other issues: inspecting the pending pool for transaction, exit the game before revealing if they know they are going to lose.

Designing a protocol for a fully decentralized game is quite a challenge.

Another subject you can search is zero knowledge proofs. There are a few tools that may help like ZoKrates, Circom.

5
  • Thank you, I'll explore your answer more in-depth, including the code, but until then I have a question: Before function awardPoint(uint256 hashedAndSaltedcolorID) is called, where should the salt be stored? I imagine using a hardcoded salt in the front-end side of the application and salting every colorID with it (colorIDs being simply positive numbers, with known hashes) would not be quite secure. Generating it randomly/uniquely for each user would open a plethora of new questions when the revealing phase occurs - where to store them, how to retrieve them etc. Commented Apr 23, 2022 at 18:58
  • For this code to work salt has to be completely random and do not depend on user properties like address, etc, or else predicting the hash would be quite easy. You don't need to store the salt in the contract, once it was revealed you can store the color value and discard the salt. Probably the best would be to store it client side and generate it when the user start playing.
    – Ismael
    Commented Apr 23, 2022 at 20:01
  • I don't understand the following: the only one who can call the "reveal" function is the admin. If I understand correctly, in order for the point to be awarded, the reveal function re-hashes colorID+salt and checks the correspondence with the commits array. How would the admin or the smart contract know those randomly generated salt values for every player in order to do that unless they are stored somewhere? And storing them in a smart contract does not seem secure, everyone can find out the salt if it's stored there. Commented Apr 26, 2022 at 18:23
  • @AndrewHoover898 That's not correct both submit & reveal are called by each participant.
    – Ismael
    Commented Apr 27, 2022 at 6:15
  • Alright, I get it now. This is problematic, because in my specific use case, there are many participants and waiting for each one to reveal their choice in order to be able to display the results is not feasible. I supposed I should be looking more for a zero knowledge proof solution, as you mentioned. Commented Apr 27, 2022 at 16:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.