0

While practising on the ethereum contract HashDice.sol using truffle, the verification of the ECDSA signature is getting invalid after running the test script.

describe('verify()', () => {
it('deploys the Test contract', async () => {
  test = await Dice.new();
});

it('returns proper address recovered from the signature', async () => {
  const msg =  1;
  const packedCommit =
            '0x' + lodash.padStart(msg.toString(16), 64, 0);
  const docHash = web3.utils.sha3(packedCommit, {
                encoding: 'hex',
            });
  console.log(`docHash:  ${docHash}`);
  console.log(`signing with account: ${accounts[1]}`);

  let sig = await web3.eth.sign(docHash, accounts[1]);
  console.log(`Signature: ${sig}`);

  let R = `0x${sig.slice(2, 66)}`
  let S = `0x${sig.slice(66, 130)}`
  let V;
  
    V = web3.utils.toDecimal(`0x${sig.slice(130, 132)}`)  + 27;
  

  console.log(`V: ${V}, R: ${R}, S: ${S}`);
  let tes = new web3.utils.BN(docHash);
  

  let result = await test.placeBet(1, 6, tes, R, S, {
    from: accounts[2],
    value: web3.utils.toWei('0.1', 'ether'),
           });
 }); });

for the method placeBet in the solidity contract.

function placeBet(uint _betMask, uint _modulo, uint _commit, bytes32 _r, bytes32 _s)
    payable
    public
  {
    Bet storage bet = bets[_commit];
    require (bet.gambler == address(0), "Bet should be in a 'clean' state.");
    bytes32 signatureHash = keccak256(abi.encodePacked(_commit));
    require (secretSigner == ecrecover(signatureHash, 27, _r, _s), "ECDSA signature is not valid.");
    uint amount = msg.value;
    require (_modulo > 1 && _modulo <= MAX_MODULO, "Modulo should be within range.");
    require (amount >= minBet && amount <= MAX_AMOUNT, "Amount should be within range.");
    require (_betMask > 0 && _betMask < MAX_BET_MASK, "Mask should be within range.");
    uint rollRange;

    if (_modulo <= MAX_MASK_MODULO) {
      // Small modulo games specify bet outcomes via bit mask.
      // rollRange is a number of 1 bits in this mask (population count).
      // This magic looking formula is an efficient way to compute population
      // count on EVM for numbers below 2**40.
      rollRange = ((_betMask * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO;
    } else {
        // Larger modulos specify the range roll game.
        uint8 lower = uint8(_betMask);
        uint8 upper = uint8(_betMask >> 8); 
        if((_betMask >> 16) == 0){
          rollRange = upper - lower + 1;    
        } else {
          rollRange = upper > lower ? _modulo - (upper-lower) + 1 : _modulo;
        }

        require ( lower > 0 &&
              upper >= lower && 
              upper <= _modulo && 
              rollRange <= _modulo * maxRollRange / 100, "Roll out of range.");
    }
      
    // Winning amount and jackpot increase.
    uint possibleWinAmount;
    uint _jackpot_fee;
    
    (possibleWinAmount, _jackpot_fee) = getDiceWinAmount(amount, _modulo, rollRange);
    
    // Enforce max profit limit.
    require (possibleWinAmount <= amount + maxProfit, "maxProfit limit violation.");
    
    // Lock funds.
    lockedInBets += uint128(possibleWinAmount);
    if(amount >= minGoldenPotBet){
      goldenPotSize += uint128(_jackpot_fee);
    }      
    else if(amount >= minSilverPotBet){
      silverPotSize += uint128(_jackpot_fee);
    }      
    
    // Check whether contract has enough funds to process this bet.
    require (goldenPotSize + silverPotSize + lockedInBets <= address(this).balance, "Cannot afford to lose this bet.");
    
    // Record commit in logs.
    emit OnCommit(_commit);
    
    // Store bet parameters on blockchain.
    bet.amount = amount;
    bet.modulo = uint8(_modulo);
    bet.rollRange = uint8(rollRange);
    bet.placeBlockNumber = uint40(block.number);
    bet.mask = uint40(_betMask);
    bet.gambler = msg.sender;
  }

I would appreciate discussions over this. Kindly advice.

4
  • The signature's V param is never used. The contract uses a hardcoded 27 in its place.
    – Ismael
    Apr 18 '20 at 0:20
  • Also web3.eth.sign will prefix your data when signing with "\x19Ethereum Signed Message:\n32", and ecrecover will not. Look at OpenZeppin code to add that prefix github.com/OpenZeppelin/openzeppelin-contracts/blob/master/….
    – Ismael
    Apr 18 '20 at 0:59
  • Yes, I have made those correction as mentioned above along with the help of github.com/kaleido-io/ecrecover, and i could see the transactions were made now in the corresponding account. But the test fails after transaction, returning : "Returned error: VM Exception while processing transaction: invalid opcode".. Could you please advice!!
    – Aldo
    Apr 18 '20 at 8:03
  • Your private testnet has not enabled some opcodes. Search for the error message, there are several answers how to fix it.
    – Ismael
    Apr 18 '20 at 16:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.