10

Given that solidity does not have any built-in string/bytes manipulation library, I was wondering what the best practice for extracting v, r, s from a signature inside solidity is.

One can encode sig as string v-r-s and use solidity-stringutils to extract them, but isn't there a better way to do this?

3
  • 1
    Out of interest why do you need to do this inside Solidity? Normally you'd pass them into your contract as separate parameters, so you don't need to mess around with them in your Solidity code. Commented Sep 15, 2017 at 11:36
  • @EdmundEdgar I'm hitting Stack too deep error, so trying to keep params # as little as possible and pass them around to other internal funcs.
    – d9ngle
    Commented Sep 15, 2017 at 12:31
  • Ah OK, makes sense. Commented Sep 15, 2017 at 19:33

4 Answers 4

8
bytes sig = ...;
bytes32 r;
bytes32 s;
uint8 v;
assembly {
  r := mload(add(sig, 32))
  s := mload(add(sig, 64))
  v := and(mload(add(sig, 65)), 255)
}
if (v < 27) v += 27;
1
  • 1
    that last line with v < 27 is super-important as the Solidity examples and Openzeppelin ECDSA contract assumes v is 27 or 28, but web3 will generate v as 0 or 1. Commented Jun 7, 2020 at 18:20
3

This works but can't return bytes32, only string.

function extractRSV(bytes sig) returns (string, string, string) {
    bytes memory r = new bytes(64);
    bytes memory s = new bytes(64);
    bytes memory v = new bytes(2);

    for (uint8 i = 0 ; i < 64 ; ++i) {
        r[i] = sig[i];
        s[i] = sig[i+64];
    }

    v[0] = sig[128];
    v[1] = sig[129];

    return (string(r), string(s), string(v));
}
2

Here's a helper library:

library ECVerify {
  function ecrecovery(bytes32 hash, bytes sig) public constant returns (address) {
    bytes32 r;
    bytes32 s;
    uint8 v;

    if (sig.length != 65) {
      return 0;
    }

    assembly {
      r := mload(add(sig, 32))
      s := mload(add(sig, 64))
      v := and(mload(add(sig, 65)), 255)
    }

    if (v < 27) {
      v += 27;
    }

    if (v != 27 && v != 28) {
      return 0;
    }

    return ecrecover(hash, v, r, s);
  }

  function ecverify(bytes32 hash, bytes sig, address signer) public constant returns (bool) {
    return signer == ecrecovery(hash, sig);
  }
}

source

0

A cool way of doing it in .sol.

pragma solidity ^0.8.4;

    contract slipt{

      function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {`
        require(sig.length == 65, "invalid signature length");

        assembly {

        // first 32 bytes, after the length prefix
        r := mload(add(sig, 32))
        // second 32 bytes
        s := mload(add(sig, 64))
        // final byte (first byte of the next 32 bytes)
        v := byte(0, mload(add(sig, 96)))
        }

        // implicitly return (r, s, v)
       }
     }

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.