Last active
January 18, 2021 14:51
-
-
Save k06a/2760049a7eda31ee7ecfc4ed3e80554a to your computer and use it in GitHub Desktop.
VanityPool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
contract VanityTask { | |
function lengthOfCommonPrefix(bytes a, bytes b) constant returns(uint) { | |
uint len = (a.length <= b.length) ? a.length : b.length; | |
for (uint i = 0; i < len; i++) { | |
if (a[i] != b[i]) { | |
return i; | |
} | |
} | |
return len; | |
} | |
function lengthOfCommonPrefix32(bytes32 a, bytes b) constant returns(uint) { | |
for (uint i = 0; i < b.length; i++) { | |
if (a[i] != b[i]) { | |
return i; | |
} | |
} | |
return b.length; | |
} | |
function equalBytesToBytes(bytes a, bytes b) constant returns (bool) { | |
if (a.length != b.length) { | |
return false; | |
} | |
for (uint i = 0; i < a.length; i++) { | |
if (a[i] != b[i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
function equalBytes32ToBytes(bytes32 a, bytes b) constant returns (bool) { | |
for (uint i = 0; i < b.length; i++) { | |
if (a[i] != b[i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
function bytesToBytes32(bytes source) constant returns (bytes32 result) { | |
assembly { | |
result := mload(add(source, 32)) | |
} | |
} | |
/* Converts given number to base58, limited by 32 symbols */ | |
function toBase58Checked(uint256 _value, byte appCode) constant returns (bytes32) { | |
string memory letters = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
bytes memory alphabet = bytes(letters); | |
uint8 base = 58; | |
uint8 len = 0; | |
uint256 remainder = 0; | |
bool needBreak = false; | |
bytes memory bytesReversed = bytes(new string(32)); | |
for (uint8 i = 0; true; i++) { | |
if(_value < base){ | |
needBreak = true; | |
} | |
remainder = _value % base; | |
_value = uint256(_value / base); | |
if (len == 32) { | |
for (uint j = 0; j < len - 1; j++) { | |
bytesReversed[j] = bytesReversed[j + 1]; | |
} | |
len--; | |
} | |
bytesReversed[len] = alphabet[remainder]; | |
len++; | |
if(needBreak){ | |
break; | |
} | |
} | |
// Reverse | |
bytes memory result = bytes(new string(32)); | |
result[0] = appCode; | |
for (i = 0; i < 31; i++) { | |
result[i + 1] = bytesReversed[len - 1 - i]; | |
} | |
return bytesToBytes32(result); | |
} | |
function complexityForBtcAddressPrefix(bytes prefix, uint length) constant returns(uint) { | |
require(prefix.length >= length); | |
//TODO: Implement more complex algo | |
// https://bitcoin.stackexchange.com/questions/48586/best-way-to-calculate-difficulty-of-generating-specific-vanity-address | |
return 58 ** length; | |
} | |
// Create BTC Address: https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address | |
function createBtcAddressHex(bytes32 publicXPoint, bytes32 publicYPoint) constant returns(bytes32) { | |
bytes20 publicKeyPart = ripemd160(sha256(0x04, publicXPoint, publicYPoint)); | |
bytes32 publicKeyCheckCode = sha256(sha256(0x00, publicKeyPart)); | |
bytes memory publicKey = new bytes(32); | |
for (uint i = 0; i < 7; i++) { | |
publicKey[i] = 0x00; | |
} | |
publicKey[7] = 0x00; // Main Network | |
for (uint j = 0; j < 20; j++) { | |
publicKey[j + 8] = publicKeyPart[j]; | |
} | |
publicKey[28] = publicKeyCheckCode[0]; | |
publicKey[29] = publicKeyCheckCode[1]; | |
publicKey[30] = publicKeyCheckCode[2]; | |
publicKey[31] = publicKeyCheckCode[3]; | |
return bytesToBytes32(publicKey); | |
} | |
function createBtcAddress(bytes32 publicXPoint, bytes32 publicYPoint) constant returns(bytes32) { | |
return toBase58Checked(uint256(createBtcAddressHex(publicXPoint, publicYPoint)), '1'); | |
} | |
//////////////////////////////////////////////////////////////////////////// | |
function test() constant returns(bool) { | |
return test_lengthOfCommonPrefix() | |
&& test_toBase58Checked() | |
&& test_createBtcAddress(); | |
} | |
function testFail() constant returns(bool) { | |
require(false); | |
return true; | |
} | |
function test_lengthOfCommonPrefix() constant returns(bool) { | |
require(lengthOfCommonPrefix("123", "456") == 0); | |
require(lengthOfCommonPrefix("123", "4567") == 0); | |
require(lengthOfCommonPrefix("1234", "456") == 0); | |
require(lengthOfCommonPrefix("123", "156") == 1); | |
require(lengthOfCommonPrefix("123", "1567") == 1); | |
require(lengthOfCommonPrefix("1234", "156") == 1); | |
require(lengthOfCommonPrefix("123", "126") == 2); | |
require(lengthOfCommonPrefix("123", "1267") == 2); | |
require(lengthOfCommonPrefix("1234", "126") == 2); | |
require(lengthOfCommonPrefix("123", "123") == 3); | |
require(lengthOfCommonPrefix("123", "1237") == 3); | |
require(lengthOfCommonPrefix("1234", "123") == 3); | |
require(lengthOfCommonPrefix("123", "") == 0); | |
require(lengthOfCommonPrefix("", "1237") == 0); | |
return true; | |
} | |
function test_toBase58Checked() constant returns(bool) { | |
require(equalBytes32ToBytes(toBase58Checked(0x00010966776006953D5567439E5E39F86A0D273BEED61967F6, '1'), "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjv")); | |
return true; | |
} | |
function test_createBtcAddressHex() constant returns(bytes32) { | |
bytes32 xPoint = bytes32(0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352); | |
bytes32 yPoint = bytes32(0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6); | |
return createBtcAddressHex(xPoint, yPoint); | |
} | |
function test_createBtcAddress() constant returns(bool) { | |
bytes32 xPoint = bytes32(0x50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352); | |
bytes32 yPoint = bytes32(0x2CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6); | |
require(equalBytes32ToBytes(createBtcAddress(xPoint, yPoint), "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjv")); | |
return true; | |
} | |
//////////////////////////////////////////////////////////////////////////// | |
struct Answer { | |
// Fetch from miner | |
address miner; | |
bytes32 answerPublicXPoint; | |
bytes32 answerPublicYPoint; | |
bytes32 answerPrivateKey; | |
// Computed by contract | |
bytes32 addressPart; | |
uint complexity; | |
bool isFinalSolution; | |
} | |
address owner; | |
VanityPool pool; | |
bytes prefix; | |
bytes32 requestPublicXPoint; | |
bytes32 requestPublicYPoint; | |
uint minAllowedLengthOfCommonPrefixForReward; | |
uint complexity; | |
uint complexitySolved = 0; | |
bool foundSolution = false; | |
Answer[] answers; | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
modifier isValidBicoinAddressPrefix(bytes prefixArg) { | |
require(prefixArg.length >= 4); | |
require(prefixArg[0] == '1' || prefixArg[0] == '3'); | |
for (uint i = 0; i < prefixArg.length; i++) { | |
byte ch = prefixArg[i]; | |
require(ch != '0' && | |
ch != 'O' && | |
ch != 'I' && | |
ch != 'l'); | |
require((ch >= '1' && ch <= '9') || | |
(ch >= 'a' && ch <= 'z') || | |
(ch >= 'A' && ch <= 'Z')); | |
} | |
_; | |
} | |
function VanityTask(address poolAddress, | |
bytes prefixArg, | |
bytes32 requestPublicXPointArg, | |
bytes32 requestPublicYPointArg) | |
isValidBicoinAddressPrefix(prefixArg) { | |
//address poolAddress = address(0x0); | |
//bytes memory prefixArg = "1Anton"; | |
//bytes32 requestPublicXPointArg = hex"141511b7dc6c3b906d88d4f7acbbabdeeec6c7ab32be5eecc1b1e6c9a6e81f09"; | |
//bytes32 requestPublicYPointArg = hex"2a26d9743e51ac77d5e8739ae507172c68cc57af727b2f57ab6e343765e476cd"; | |
// hex"611b5ca5f79aefd448f728421e8b3329364fd86458418052e5e1023e74879ec7" | |
owner = msg.sender; | |
pool = VanityPool(poolAddress); | |
prefix = prefixArg; | |
requestPublicXPoint = requestPublicXPointArg; | |
requestPublicYPoint = requestPublicYPointArg; | |
minAllowedLengthOfCommonPrefixForReward = prefix.length - 2; | |
complexity = complexityForBtcAddressPrefix(prefix, prefix.length); | |
if (pool != address(0x0)) { | |
pool.registerTask(); | |
} | |
} | |
function kill() onlyOwner() { | |
VanityPool vanityPool = pool; | |
selfdestruct(owner); | |
if (vanityPool != address(0x0)) { | |
vanityPool.removeTask(); | |
} | |
} | |
function () payable { | |
if (pool != address(0x0)) { | |
pool.updateTask(); | |
} | |
} | |
function redeem(uint amount) onlyOwner() { | |
owner.transfer(amount); | |
if (pool != address(0x0)) { | |
pool.updateTask(); | |
} | |
} | |
// https://github.com/stonecoldpat/anonymousvoting/blob/master/LocalCrypto.sol | |
function invmod(uint a, uint p) internal constant returns (uint) { | |
if (a == 0 || a == p || p == 0) | |
return 0; | |
if (a > p) | |
a = a % p; | |
int t1; | |
int t2 = 1; | |
uint r1 = p; | |
uint r2 = a; | |
uint q; | |
while (r2 != 0) { | |
q = r1 / r2; | |
(t1, t2, r1, r2) = (t2, t1 - int(q) * t2, r2, r1 - q * r2); | |
} | |
if (t1 < 0) | |
return (p - uint(-t1)); | |
return uint(t1); | |
} | |
// https://github.com/stonecoldpat/anonymousvoting/blob/master/LocalCrypto.sol | |
function submod(uint a, uint b, uint m) returns (uint){ | |
uint a_nn; | |
if (a > b) { | |
a_nn = a; | |
} else { | |
a_nn = a + m; | |
} | |
return addmod(a_nn - b, 0, m); | |
} | |
// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition | |
// https://github.com/bellaj/Blockchain/blob/6bffb47afae6a2a70903a26d215484cf8ff03859/ecdsa_bitcoin.pdf | |
// https://math.stackexchange.com/questions/2198139/elliptic-curve-formulas-for-point-addition | |
function addXY(uint x1, uint y1, uint x2, uint y2) returns(bytes32 x3, bytes32 y3) { | |
uint m = uint(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f); | |
uint anti = invmod(submod(x2, x1, m), m); | |
uint alpha = mulmod(submod(y2, y1, m), anti, m); | |
x3 = bytes32(submod(submod(mulmod(alpha, alpha, m), x2, m), x1, m)); | |
y3 = bytes32(submod(mulmod(alpha, submod(x1, uint(x3), m), m), y1, m)); | |
// x3 = bytes32(mul_mod(uint(x3), uint(y3), m)); == 1!!!! | |
// https://github.com/jbaylina/ecsol/blob/master/ec.sol | |
//(x3, y3) = ( bytes32(addmod( mulmod(y2, x1 , m) , | |
// mulmod(x2, y1 , m), | |
// m)), | |
// bytes32(mulmod(y1, y2 , m)) | |
// ); | |
} | |
function postAnswerCheck(bytes32 answerPublicXPoint, bytes32 answerPublicYPoint) constant returns(uint) { | |
//bytes32 answerPublicXPoint = hex"bef8aa5dc83f75aff0e42f10b923e01e76d2f1d830e1a89dfe8621975a6226fe"; | |
//bytes32 answerPublicYPoint = hex"6da72eaa3180aef4a0213e5430a6eb11a3b88f04914c7037e4bf1f499b11f8d5"; | |
//bytes32 answerPrivateKey = bytes32(hex"eaf58f3ebd5ad92c16528b43ac41dadf267e50126568dcdd8a9196d469516659"); | |
var (publicXPoint, publicYPoint) = addXY(uint(requestPublicXPoint), uint(requestPublicYPoint), uint(answerPublicXPoint), uint(answerPublicYPoint)); | |
bytes32 btcAddress = createBtcAddress(publicXPoint, publicYPoint); | |
uint prefixLength = lengthOfCommonPrefix32(btcAddress, prefix); | |
return prefixLength; | |
} | |
function postAnswer(bytes32 answerPublicXPoint, bytes32 answerPublicYPoint, bytes32 answerPrivateKey) returns(bool) { | |
// Check private key generates exact same public key | |
// https://github.com/sontol/secp256k1evm | |
// require(TODO!) | |
var (publicXPoint, publicYPoint) = addXY(uint(requestPublicXPoint), uint(requestPublicYPoint), uint(answerPublicXPoint), uint(answerPublicYPoint)); | |
bytes32 btcAddress = createBtcAddress(publicXPoint, publicYPoint); | |
uint prefixLength = lengthOfCommonPrefix32(btcAddress, prefix); | |
require(prefixLength >= minAllowedLengthOfCommonPrefixForReward); | |
Answer memory answer = Answer( | |
msg.sender, | |
answerPublicXPoint, | |
answerPublicYPoint, | |
answerPrivateKey, | |
btcAddress, | |
complexityForBtcAddressPrefix(prefix, prefixLength), | |
false); | |
if (prefixLength == prefix.length) { | |
// Final answer | |
answer.isFinalSolution = true; | |
foundSolution = true; | |
} | |
else if (prefixLength >= minAllowedLengthOfCommonPrefixForReward) { | |
// Good answer | |
answer.isFinalSolution = false; | |
} | |
else { | |
// Wrong answer | |
revert(); | |
} | |
answers.push(answer); | |
uint amount = this.balance * answer.complexity / (complexity - complexitySolved); | |
if (amount > this.balance) { | |
amount = this.balance; | |
} | |
uint fee = 0; | |
if (pool != address(0x0)) { | |
fee = amount / 100; | |
amount -= fee; | |
} | |
msg.sender.transfer(amount); // TODO: Danger! Handle recursive call! | |
complexitySolved += answer.complexity; | |
if (pool != address(0x0)) { | |
pool.updateTask(); | |
pool.transfer(fee); | |
} | |
return true; | |
} | |
} | |
contract VanityPool { | |
address owner; | |
VanityTask[] tasks; | |
event TaskRegistered(VanityTask task); | |
event TaskUpdated(VanityTask task); | |
event TaskRemoved(); | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
function isTaskRegistered(address task) returns(bool) { | |
for (uint i = 0; i < tasks.length; i++) { | |
if (tasks[i] == task) { | |
return true; | |
} | |
} | |
return false; | |
} | |
modifier onlyRegisteredTask(address task) { | |
require(isTaskRegistered(task)); | |
_; | |
} | |
modifier onlyNotRegisteredTask(address task) { | |
require(!isTaskRegistered(task)); | |
_; | |
} | |
function VanityPool() { | |
owner = msg.sender; | |
tasks = new VanityTask[](0); | |
} | |
function () payable { | |
} | |
function redeem(uint amount) onlyOwner() { | |
owner.transfer(amount); | |
} | |
function registerTask() onlyNotRegisteredTask(msg.sender) { | |
VanityTask task = VanityTask(msg.sender); | |
tasks.push(task); | |
TaskRegistered(task); | |
} | |
function updateTask() onlyRegisteredTask(msg.sender) { | |
VanityTask task = VanityTask(msg.sender); | |
TaskUpdated(task); | |
} | |
function removeTask() onlyRegisteredTask(msg.sender) { | |
VanityTask task = VanityTask(msg.sender); | |
for (uint i = 0; i < tasks.length; i++) { | |
if (tasks[i] == task) { | |
delete tasks[i]; | |
for (uint j = i; j < tasks.length - 1; j++) { | |
tasks[j] = tasks[j + 1]; | |
} | |
tasks.length--; | |
TaskRemoved(); | |
break; | |
} | |
} | |
revert(); | |
} | |
} | |
contract BitValid { | |
bytes32 constant mask4 = 0xffffffff00000000000000000000000000000000000000000000000000000000; | |
bytes1 constant networkConst = 0x00; | |
function getBitcoinAddress( | |
bytes32 _xPoint, | |
bytes32 _yPoint) | |
constant | |
returns( | |
bytes20 hashedPubKey, | |
bytes4 checkSum, | |
bytes1 network) | |
{ | |
hashedPubKey = getHashedPublicKey(_xPoint, _yPoint); | |
checkSum = getCheckSum(hashedPubKey, networkConst); | |
network = networkConst; | |
} | |
function getHashedPublicKey( | |
bytes32 _xPoint, | |
bytes32 _yPoint) | |
constant | |
returns( | |
bytes20 hashedPubKey) | |
{ | |
uint8 startingByte = 0x04; | |
return ripemd160(sha256(startingByte, _xPoint, _yPoint)); | |
} | |
function getCheckSum( | |
bytes20 _hashedPubKey, | |
bytes1 network) | |
constant | |
returns( | |
bytes4 checkSum) | |
{ | |
var full = sha256((sha256(network, _hashedPubKey))); | |
return bytes4(full & mask4); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment