10

Sorry if you find these questions are basic, but I am new to encryption. As far as I know, Solidity have ecrecover function for this purpose, but it use secp256k1 signature. which I am intend to use secp256r1. I used the following steps in this gist to get r,s, an v values.

Then I applied all secp256r1 verification from WIKIpedia as follow

 1. getting r,s, and v values. 
 2. verify that r, s are integers in [1,n-1].
 3. calculate the hashing of the message.
 4. calculate w = s^-1 mod n
 5. calculate the curve point (x1,y1) = u1 x G + u2 x Q

Hint: ecadd is adding point function I wrote. ecmul is a multiplication function, isPoint: check if the point is in the curve or not.

My questions are,

1- do I wrote the five steps of the equation correctly; I am not of the 4th and 5th steps. You can check the code of the verification function for further details.

2- if I want to check the verification. I should send a message and a signature. do I need to return more than True/False for verification.

// testing signature function
// getting r, s, and v values from signature.
// steps would be as follows
// 1. getting r,s, and v values.
function ectest(bytes32 hash, bytes sig) returns (bool) {
    bytes32 r;
    bytes32 s;
    uint8 v;

    if (sig.length != 65)
      return (false, 0);

    // The signature format is a compact form of:
    //   {bytes32 r}{bytes32 s}{uint8 v}
    // Compact means, uint8 is not padded to 32 bytes.
assembly {
    r := mload(add(sig, 32))
    s := mload(add(sig, 64))

    // Here we are loading the last 32 bytes. We exploit the fact that
    // 'mload' will pad with zeroes if we overread.
    // There is no 'mload8' to do this, but that would be nicer.
    v := byte(0, mload(add(sig, 96)))

    // Alternative solution:
    // 'byte' is not working due to the Solidity parser, so lets
    // use the second best option, 'and'
    // v := and(mload(add(sig, 65)), 255)
}

// albeit non-transactional signatures are not specified by the YP, one would expect it
// to match the YP range of [27, 28]

if (v < 27)
  v += 27;

if (v != 27 && v != 28)
    return (false, 0);

// 2. verify that r, s are integers in [1,n-1] using isPoint function
if(isPoint(r,s) == false)
{
  return (false, 0);
}


//3. calculate the hashing of the message
e = sha3(msg);

//4. let v be the leftmost bits of msg
// calculate above in the assembly code
// v



      //5. calculate w = s^-1 mod n
      w  = invmod(s,n);
      // u1 = v * w mod n
      u1 = (v * w) % n ;
      // u2 = r * w mod n
      u2 = (r * w) % n;

      //6. calculate the curve point (x1,y1) = u1 x G + u2 x Q
      (x3,y3)=  ecmul(gx,gy,u1);
      (x4,y4)= ecmul(gx,gy,u2);

      (x1,y1) = ecadd(x3,y3,x4,y4);
      //7. check the validation
      if (r == x1)
      {
        return (true);
      }
    }// end function

}

2
  • 1
    I'm disappointed that no one addresses his question. People assumed that he was asking about secp256k1. Apr 21, 2018 at 8:16
  • Ah. Sorry, after reading the previous comment, I see he wants the secp256r1 curve.
    – RicMoo
    Jun 11, 2018 at 7:06

4 Answers 4

2

This is an imporant question, since all of the other world (mobile, smartcards, HSM's etc) uses secp256r1.

There's an article at http://blog.enuma.io/update/2016/11/01/a-tale-of-two-curves-hardware-signing-for-ethereum.html

but unfortunately the codes actually implementing the functionality have disappeared. Planning to reverse engineer this from the bytecode, but it might take some time...

1
  • the link seems not working, Im seeking for a solidity implementation of signing function. any idea? Feb 28 at 18:04
2

There's a pure solidity implementation of SECP256R1 / P256 / PRIME256V1 at https://github.com/tdrerup/elliptic-curve-solidity.

Main drawback is probably that verifying a non-native signature in Solidity is fairly expensive. The repo includes some truffle tests that should be helpful to understand the formatting of the variables.

-1

Be carefull when you use the sign-function of web3js because it does some strange prefixing before signing.

I made a tutorial on how to sign and verify data with solidity and web3js.

-2

1) The ecrecover function is built into solidity, so you don't need all those steps.

2) It really depends on what you are doing with it. Keep in mind if you are signing a message (i.e. eth_personalSign) there is a message prefix prepended to the signed message, the string "\x19Ethereum Signed Message:\n" followed by the length of the message.

Using ecrecover is a bit complicated at first, but once you master it, an amazing world of possibilities is at your fingertips.


Example Solidity Contract:

contract Foobar {
    function checkSignature(bytes32 digest, uint8 v, bytes32 r, byres32 s) constant returns (address signer) {
        return ecrecover(digest, v, r, s);
    }
}

Example JavaScript:

var ethers = require('ethers');

var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
var signingKey = new ethers.SigningKey(privateKey);
// SigningKey {
//    privateKey: '0x0123456789012345678901234567890123456789012345678901234567890123',
//    publicKey: '0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515',
//    address: '0x14791697260E4c9A71f18484C9f997B308e59325',
// }

// The id function computes the keccak256 of a utf-8 string
var digest = ethers.utils.id("Hello World);
// '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba'

var sig = signingKey.signMessage(digest);
// { 
//    recoveryParam: 0,
//    r: '0x79f56f3422dc67f57b2aeeb0b20295a99ec90420b203177f83d419c98beda7fe',
//    s: '0x1a9d05433883bdc7e6d882740f4ea7921ef458a61b2cfe6197c2bb1bc47236fd'
// }

var contract = new ethers.Contract( ... )

// The v needs 27 added to it; this is legacy from a Bitcoin standard
var req = contract.checkSig(digest, sig.recoveryParam + 27, sig.r, sig.s);

// Call the Solidity function
req.then(function(signer) {
    console.log(signer);
    // "0x14791697260E4c9A71f18484C9f997B308e59325"
});

Real World Example:

Here is a quick Sticker Registry I created for the Firefly sticker promotional campaign. Each sticker is procedurally generated and unique, and had a private key on the back, which could be used to redeem the sticker. But the private key has no funds. Instead a user uses their own funds to pay the gas to submit a message signed by the sticker's private key. The contract verifies the sticker is valid using ecrecover and looking up the sticker in a merkle tree and the sticker is then transferred to the user.

https://etherscan.io/address/0xb90e64082d00437e65a76d4c8187596bc213480a#code

1
  • ecrecover expects Ed25519 signatures I believe Jan 16, 2022 at 5:38

Your Answer

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

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