Added draft of the first challenge

pull/507/head
szotov 2018-10-10 17:53:58 +03:00
parent 014a1094ab
commit 0e06d67252
4 changed files with 144 additions and 9 deletions

View File

@ -0,0 +1,103 @@
pragma solidity ^0.4.25;
import "./lib/SignatureVerifier.sol";
/**
* @notice Challenges for NuCypher net characters
* @dev TODO move or integrate with MinersEscrow
**/
contract ChallengeLibrary {
uint256 constant PENALTY = 100; // TODO
MinersEscrowStub public escrow;
SignatureVerifier.HashAlgorithm public hashAlgorithm;
mapping (bytes32 => bool) public challengedCFrags;
/**
* @param _escrow Escrow contract
* @param _hashAlgorithm Hashing algorithm
**/
constructor(
MinersEscrowStub _escrow,
SignatureVerifier.HashAlgorithm _hashAlgorithm
) public {
require(address(_escrow) != 0x0);
escrow = _escrow;
hashAlgorithm = _hashAlgorithm;
}
/**
* @notice Submit proof that miner create wrong CFrag
* @param _capsuleBytes Serialized capsule
* @param _cFragBytes Serialized CFrag
* @param _signature Signature of Capsule and CFrag
* @param _minerPublicKey Miner's public key that was used to sign Capsule and CFrag
* @param _minerPublicKeySignature Signature of public key by miner's eth-key
**/
function challengeCFrag(
bytes _capsuleBytes,
bytes _cFragBytes,
bytes _signature,
bytes _minerPublicKey,
bytes _minerPublicKeySignature
) public {
require(_minerPublicKey.length == 65);
bytes memory signedData = abi.encodePacked(_capsuleBytes, _cFragBytes);
// copy public key except first byte
bytes memory preparedPublicKey = new bytes(64);
assembly {
let destination := add(mload(preparedPublicKey), 32)
let source := add(mload(_minerPublicKey), 33)
mstore(destination, mload(source))
mstore(add(destination, 32), mload(add(source, 32)))
}
bytes32 dataHash = SignatureVerifier.hash(signedData, hashAlgorithm);
require(SignatureVerifier.toAddress(preparedPublicKey) ==
SignatureVerifier.recover(dataHash, _signature));
require(!challengedCFrags[dataHash]); // CFrag is not challenged yet
bytes32 publicKeyHash = SignatureVerifier.hash(_minerPublicKey, hashAlgorithm);
address miner = SignatureVerifier.recover(publicKeyHash, _minerPublicKeySignature);
require(escrow.getLockedTokens(miner) > 0); // TODO check that miner can be slashed
if (!check(_capsuleBytes, _cFragBytes)) {
escrow.slashMiner(miner, PENALTY);
}
challengedCFrags[dataHash] = true;
}
// TODO complete
function check(
bytes _capsuleBytes,
bytes _cFragBytes
) public returns (bool) {
return false;
}
}
// TODO move to tests
contract MinersEscrowStub {
mapping (address => uint256) public minerInfo;
function setMinerInfo(address _miner, uint256 _amount) public {
minerInfo[_miner] = _amount;
}
function getLockedTokens(address _miner)
public view returns (uint256)
{
return minerInfo[_miner];
}
function slashMiner(address _miner, uint256 _amount) public {
minerInfo[_miner] -= _amount;
}
}

View File

@ -46,6 +46,25 @@ library SignatureVerifier {
return address(keccak256(_publicKey));
}
/**
* @notice Hash using one of pre built hashing algorithm
* @param _message Signed message
* @param _algorithm Hashing algorithm
**/
function hash(bytes _message, HashAlgorithm _algorithm)
internal
pure
returns (bytes32 result)
{
if (_algorithm == HashAlgorithm.KECCAK256) {
result = keccak256(_message);
} else if (_algorithm == HashAlgorithm.SHA256) {
result = sha256(_message);
} else {
result = ripemd160(_message);
}
}
/**
* @notice Verify ECDSA signature
* @dev Uses one of pre built hashing algorithm
@ -59,15 +78,7 @@ library SignatureVerifier {
pure
returns (bool)
{
bytes32 hash;
if (_algorithm == HashAlgorithm.KECCAK256) {
hash = keccak256(_message);
} else if (_algorithm == HashAlgorithm.SHA256) {
hash = sha256(_message);
} else {
hash = ripemd160(_message);
}
return toAddress(_publicKey) == recover(hash, _signature);
return toAddress(_publicKey) == recover(hash(_message, _algorithm), _signature);
}
}

View File

@ -91,6 +91,19 @@ def test_address(testerchain, signature_verifier):
assert signer_address == to_normalized_address(result_address)
@pytest.mark.slow
def test_hash(testerchain, signature_verifier):
message = os.urandom(100)
# Prepare message hash
hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
hash_ctx.update(message)
message_hash = hash_ctx.finalize()
# Verify hash function
assert message_hash == signature_verifier.functions.hash(message, ALGORITHM_SHA256).call()
@pytest.mark.slow
def test_verify(testerchain, signature_verifier):
message = os.urandom(100)

View File

@ -21,6 +21,14 @@ contract SignatureVerifierMock {
return SignatureVerifier.toAddress(_publicKey);
}
function hash(bytes _message, SignatureVerifier.HashAlgorithm _algorithm)
public
pure
returns (bytes32 result)
{
return SignatureVerifier.hash(_message, _algorithm);
}
function verify(bytes _message, bytes _signature, bytes _publicKey, SignatureVerifier.HashAlgorithm _algorithm)
public
pure