Signature generation and verification in solidity

galanogiuseppegalanogiuseppe Member Posts: 3
Hi everyone!
I'd like to develop a smart contract that uses public key cryptography, in particular cryptographic signature algorithms.

Are there, in solidity, some primitives to generate and check cryptographic signatures?

Thanks and keep up the good work,
Giuseppe

Comments

  • chrisethchriseth Member Posts: 170 ✭✭✭
    You can check bitcoin-style signatures using "ecrecover" or (if this is sufficient) you can rely on the fact that every transaction has to be signed, the signature is verified by the client and has to match the public key corresponding to tx.sender.
  • galanogiuseppegalanogiuseppe Member Posts: 3
    edited April 2017
    Many thanks Chris.
    Probably ecrecover could be the right tool for me.

    Do you know the meaning of the parameters passed to the ecrecover function?
    ecrecover(bytes32, byte, bytes32, bytes32) returns (address)
    There are 4 parameters. Thinking about ECDSA signatures, there should be the data, the signature (r and s) and the public key.
    I'm not able to figure out how parameters should be passed to ecrecover and why the return type is address and not a boolean.

    Are there some examples of ecrecover usage?
    Post edited by o0ragman0o on
  • chrisethchriseth Member Posts: 170 ✭✭✭
    edited May 2015
    The names of the parameters are:
    ecrecover(bytes32 hash, byte v, bytes32 r, bytes32 s)

    The idea of ecrecover is that it is possible to compute the public key corresponding to the private key that was used to create an ECDSA signature given two additional bits which are usually supplied with the signature. The signature itself is the two (encoding of the) elliptic curve points r and s and v is the two additional bits needed to recover the public key.
    This also explains why the return type is address: It returns the address corresponding to the recovered public key (i.e. its sha3/keccak hash). This means to actually verify the signature, you check whether the returned address is equal to the one whose corresponding private key should have signed the hash.

    You can generate the signature using e.g. the pybitcointools. The functions decode_sig and ecdsa_raw_sign should be useful.
  • galanogiuseppegalanogiuseppe Member Posts: 3
    edited April 2017
    Many thanks again chriseth!

    I did some experiments in python, I run the following commands:
    from bitcoin import *
    message = "Sign this important message"
    privkey = random_key()
    print 'privkey', privkey
    pubkey = privtopub(privkey)
    print 'pubkey', pubkey
    print 'address', pubkey_to_address(pubkey)
    messageHash = sha256(message)
    vrs = ecdsa_raw_sign(messageHash,privkey)
    print 'vrs',vrs
    print 'v binary string',bin(vrs[0])
    recoveredPublicKey = ecdsa_raw_recover(messageHash, vrs)
    print 'recovered Pub Key', recoveredPublicKey
    print 'recovered Address', pubtoaddr(recoveredPublicKey)
    Obtaining this results:
    privkey 03d665becb7ea80247bc758a2066b28c5cecf7a2eaf5912d59c983dbd1a82827
    pubkey 041fc5a6d30578aff08faa82373495d1fbd92f5b460ee9d6b3014a28a6d7178b0525b49bcf1054350f7ec7e6a660c09227eb3a91b87f991a845a361e2b8c72e1d9
    address 191tA7vdhHfxJ7ADprt5WoL5FuhNFCSytp
    vrs (27L, 86146593949355609528570051649674383651435874365752838751003869604681112877581L, 13702707919972591320949771619453281682723600718609188644145704130336118937744L)
    v binary string 0b11011
    recovered Pub Key (14370918556861123074121934630691462840420276177415733724914307643908619209477L, 17054683222353315714089667151791370304750325956199064329489506434626706661849L)
    recovered Address 191tA7vdhHfxJ7ADprt5WoL5FuhNFCSytp
    Everything just worked as expected.
    I'm wondering why the value of v is always either 27 (11011) or 28 (11100). Why does ecrecover need two bits for v if there are only two possible values for it?

    Next step is trying verify the signature with solidity in a smart contract.
    What is the encoding for r and s?
    Post edited by o0ragman0o on
  • chrisethchriseth Member Posts: 170 ✭✭✭
    If you enter r and s as decimal numbers, I guess it should just work, i.e. there is no encoding (apart from the standard ABI encoding).
    I think for general curves, v needs to be two bits, but for secp256k1 only one is needed, I think this is because the used group's cofactor is one.

    Ah and one warning concerning the "precompiled contracts" sha256, ecrecover and ripemd160:
    If you use them on a private chain you might get an Out-of-Gas error. This is because sending internal messages to addresses is more expensive if they do not exist yet. The code for these precompiled contracts does exist (as it is hardcoded in the clients), but the addresses are not marked as existing until they receive the first message. So either specify the gas manually by ecrecover.gas(5000)(hash, v, r, s) or send a transaction to it first. This is of course not a problem on the official and test net.
  • SmithgiftSmithgift Member Posts: 64
    edited May 2015
    @chriseth: Is it possible to call these precompiled contracts from outside solidity (i.e. from the JS API?)

    I ask because web3's sha only works with strings, but I need to sha3 two numbers together. At the moment I'm just calling (not transacting to) a kludge contract, but if there's something that already exists I'd prefer to just call it.

    EDIT: Specifically, my problem is that 0x31, the character '1', is not the same as 0x01, or the integer one.
  • chrisethchriseth Member Posts: 170 ✭✭✭
    sha is not a precompiled contract but an EVM opcode. I guess that you can call sha on the "numbers" if you convert them to hex strings, but I do not really know the web3.js framework.
  • SmithgiftSmithgift Member Posts: 64
    The problem is that when the contract re-sha3s the number in the future to compare it to the preimage, I have to use the exact same input. The hash of the four bytes that make the string "0xFF", to pick an example, is not the same as the hash of the single byte 0xFF. I considered converting the numbers byte-by-byte into a string, but if I end up with a \0 somewhere in there, then the string breaks.

    I think I'll raise this on GitHub. I'm sure someone else will crash into this eventually.
  • cryptoboycryptoboy Member Posts: 74
    Any word on this? Has anyone successfully verified BTC signature within ETH?
  • RCasattaRCasatta Member Posts: 7
    I succesfully verified a BTC signature in a solidity smart contract
    see this commit for the example code:
    https://github.com/bertani/poolicy/commit/49987b60968104586a4f481ed621d18010fd58be
Sign In or Register to comment.