aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src/contracts/current/protocol/Exchange/MixinSignatureValidator.sol
blob: 7edb5a372cf2e7e78ac60a2bd0e9b165934d42af (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*

  Copyright 2017 ZeroEx Intl.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

pragma solidity ^0.4.19;

import "./mixins/MSignatureValidator.sol";
import "./ISigner.sol";

/// @dev Provides MSignatureValidator
contract MixinSignatureValidator is
    MSignatureValidator
{
    enum SignatureType {
        Invalid,
        Caller,
        Ecrecover,
        Contract
    }
  
    function isValidSignature(
        bytes32 hash,
        address signer,
        bytes signature)
        public view
        returns (bool isValid)
    {
        // TODO: Domain separation: make hash depend on role. (Taker sig should not be valid as maker sig, etc.)
        
        require(signature.length >= 1);
        SignatureType signatureType = SignatureType(uint8(signature[0]));
        
        // Zero is always an invalid signature
        if (signatureType == SignatureType.Invalid) {
            require(signature.length == 1);
            isValid = false;
            return;
        
        // Implicitly signed by caller
        } else if (signatureType == SignatureType.Caller) {
            require(signature.length == 1);
            isValid = signer == msg.sender;
            return;
        
        // Signed using web3.eth_sign
        } else if (signatureType == SignatureType.Ecrecover) {
            require(signature.length == 66);
            uint8 v = uint8(signature[1]);
            bytes32 r = get32(signature, 2);
            bytes32 s = get32(signature, 34);
            address recovered = ecrecover(
                keccak256("\x19Ethereum Signed Message:\n32", hash),
                v,
                r,
                s
            );
            isValid = signer == recovered;
            return;
        
        // Signature verified by signer contract
        } else if (signatureType == SignatureType.Contract) {
            isValid = ISigner(signer).isValidSignature(hash, signature);
            return;
        }
        
        // Anything else is illegal (We do not return false because
        // the signature may actually be valid, just not in a format
        // that we currently support. In this case returning false
        // may lead the caller to incorrectly believe that the
        // signature was invalid.)
        revert();
    }
    
    function get32(bytes b, uint256 index)
        private pure
        returns (bytes32 result)
    {
        require(b.length >= index + 32);
        
        // Arrays are prefixed by a 256 bit length parameter
        index += 32;
        
        // Read the bytes32 from array memory
        assembly {
            result := mload(add(b, index))
        }
    }

}