I want my smart contract to return 7 or 8 UNIQUE random numbers ranging from 1 to 100 upon calling the contract. What can be the best approach to obtain such result?
Probably if you are trying to build roulettes, lotteries, and card games using the Ethereum blockchain, as the Ethereum blockchain is deterministic, it imposes certain difficulties for those who have chosen to write their own pseudo-random number generator (PRNG).
Some Vulnerable Methods Currently Used
If you are using the block variables like block.coinbase, block.difficulty, block.timestamp etc.. as the source of entropy, all these block variables can be manipulated by miners, so they cannot be used as a source of entropy because of the miners’ incentive. As the block variables are obviously shared within the same block, you can easily use internal messages to yield the same outcome.
Other methods are like using blockhash of current or some past block
or blockhash of a past block combined with a private seed. block.blockhash(block.number) function is used in these cases. However, at the moment of transaction execution in the EVM, the blockhash of the block that is being created is not yet known for obvious reasons and the EVM will always yield zero. If we are trying it with the blockhash of a previous block, an attacker can make an exploit contract with the same code in order to call the target contract via an internal message. The “random” numbers for the two contracts will be the same.
Even if we combine the blockhash with a private seed, being transparent in nature, the blockchain must not be used to store secrets in plaintext. It is trivial to extract the value of the private variable pointer from the contract storage and supply it as an argument to an exploit.
Some Areas Worth Exploring
External oracles
Signidice
Commit–reveal approach
With External oracles like Oraclize, smart contracts can request data from web APIs such as currency exchange rates, weather forecasts, and stock prices (like random.org). The key drawback of this approach is that it is centralized. Will Oraclize daemon tamper with the results? Can we trust random.org?
Instead of Oraclize, we can also use BTCRelay which is a bridge between Ethereum and Bitcoin blockchains. Using BTCRelay, smart contracts in the Ethereum blockchain can request future Bitcoin blockhashes and use them as a source of entropy.
Signidice is an algorithm based on cryptographic signatures that can be used for random number generation in smart contracts involving only two parties: the player and the house. The algorithm works as follows:
The player makes a bet by calling a smart contract.
The house sees the bet, signs it with its private key, and sends the signature to the smart contract.
The smart contract verifies the signature using the known public key.
This signature is then used to generate a random number.
Commit–reveal approach consists of two phases:
A “commit” stage, when the parties submit their cryptographically protected secrets to the smart contract.
A “reveal” stage, when the parties announce cleartext seeds, the smart contract verifies that they are correct, and the seeds are used to generate a random number.
A better implementation of the commit–reveal approach is Randao. Commit–reveal can be combined with future blockhashes to make it more secure.
This pretty much covers all the methods for random number generation using Ethereum.
Like Raghav said, random numbers on the blockchain are hard. The public nature of the network makes it very hard to generate a number that cannot be pre-calculated.
With that said, one of the best solutions is to use an oracle that gets the random number from an external (read: non-blockchain based) source. Take a look at this guide. The Ethtroll Dapp is a good example of this, so take a look at the code here. They use Oraclize to get a random number from Random.org.
An issue with using an oracle is the centralization factor. If you set up your Dapp in the way I have described above, you are at the mercy of a rouge employee at two different centralized services—Oraclize and Random.org. Though it would be unlikely for someone to manipulate either of these sources, people will perform irrational acts for potential economic gain.
Use a Chainlink VRF.
There are a number of issues with using the blockhash or similar as the method of random seeding. If an attacker knows the blockhash before your contract, they can use that information to gain a malicious advantage on whatever it is you're trying to do. An oracle can help here, but they are a central source of failure and must be able to prove they are random.
You need to have an oracle network that can:
Prove that the numbers generated are random.
Have enough oracles/nodes that even if one fails/is corrupt, your smart contract will persist.
At this time, the example below shows how to solve #1. You can solve #2 by pulling from a sufficient number of nodes who support the Chainlink VRF.
For an exact implementation, see this answer from a similar question.
You'll want to make a request to a node with a function that takes a seed generated by you:
function rollDice(uint256 userProvidedSeed) public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) > fee, "Not enough LINK - fill contract with faucet");
uint256 seed = uint256(keccak256(abi.encode(userProvidedSeed, blockhash(block.number)))); // Hash user seed and blockhash
bytes32 _requestId = requestRandomness(keyHash, fee, seed);
emit RequestRandomness(_requestId, keyHash, seed);
return _requestId;
}
And when the value is returned, you'll mod it by 100 and add 1. You'll need to call this 7 or 8 times if you want 7 or 8 random numbers.
function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
uint256 d6Result = randomness.mod(100).add(1);
emit RequestRandomnessFulfilled(requestId, randomness);
}
I have a brainstorming idea, maybe helps somebody.
It is a simplified Commit–reveal approach with just one participant.
It wil be needed a title for every random generation. That tittle should be and standard, and easy to audit.
First I Commit("Alice's Lotery") on the smartContract. If title is repeated (check hashes) it will be rejected.
And for reveal will be needed to wait at least 1 extra block confirmation, this 2 blocks should come from different miners to ensure miner is not attacking this smartcontract.
And then you execute Reveal("Alberto's Lottery").
The magic happens here; The sources for random will be the titlle, msg.sender, block.blockhash of the commit block, and the block.blockhash(commitBlockNumber+1) because nobody can predict the future hash nor which miner will discover it [you could add coinbase or timestamp also to get more random value].
Also you could check if timestamps of commitBlockNumber and commitBlockNumber+1 are too much close or too much separated, this could indicate that some minner is trying to force some block, so you could reject this lottery.
And of course if you can watch too much close tx with commits like ("Alice's Lottery") || ("AAlice's Lottery") you can probe that this lottery is being tricked.
Also you could do this with more than 2 "interval" blocks
Related
I read here about the standard way to generate random numbers in solidity using keccak256 and timestamp, contract caller and nonce as a source of entropy.
I also read in the article linked above that the main problem with this method is that when the caller of the contract also has his own node, he can publish infinite transactions to his own node, but not share them, until he generated the number he wants.
My question is, in case that my smart contract is meant to be called just from the trusted source, is then this method of generating random numbers safe?
I am also wondering if I generate a new Ethereum address each time to call the contract, does that add to the entropy, and make the number impossible to predict?
It seems to me that generating new address each time adds enough entropy and in a way the source that generates the addresses and calls the contract plays a role of an oracle. Is that right?
Any random number generated in a smart contract can be guessed beforehand by someone. Thus any random number generated in a smart contract is insecure.
If you call the smart contract from the trusted source, you can as well generate the random number in the trusted source and not be kicking the can down the road. Generating addresses is just smoke and mirrors as of course, someone knows what addresses they are generating.
What I understand about blockchain is that:
Blocks are secured by the hash.
Transactions are secured by the markle-tree.
Does this mean that the markle-tree is not involved at all in securing the blocks?
If so, what prevents us from changing the transactions if we know the hash of older blocks in the chain?
Please note that I'm assuming that we are using a blockchain with only one node. And I want to know how hard it is to hack the blockchain in one node. Because as far as i understand, the hashing alone is very secure, but distributing the blockchain on multiple nodes will make it even more secure.
Blocks are secured with the proof of work. The proof of work is a measure related to how many hashes (on average) it would take to get a block hash equal to the network target value. The lower the target value, the more work was done on the block, and the harder it is to change or "hack" the data in the block and still remain a valid block (because you must do the work again).
The merkle root is just a way to represent all of the transactions in the block in a single hash value, which is part of the data that is hashed to produce the block hash. If you change any of the transaction data, it will produce a different merkle root, and that will make the resulting block hash different too, and now the proof of work must be done again before the block would be considered valid.
Now, with only one node, it does not matter. If you are able to change the data in a block and rehash that block with a new valid hash (one that is equal to or lower than the network target value), you have a new block, but the node will reject it because it already has that block. You must mine the next block also before anyone else because one of the consensus rules is that the longest valid chain always wins.
Having only one node running means that node can be changed by the person who is running it, possibly without anyone else knowing. This might remove certain rules that you thought we're being followed, which could reverse one of your transactions, so it is good to run your own node to make sure the rules are being followed.
I need a unique identifier to distinguish entities, but in reality these entities don't have a lot, and the uid can be repeated when the entity is destroyed. Entities are created in a distributed system and can be created multiple times at the same time.
Currently using a popular UUID library, but UUID is a 128-bit number. According to the design of my system, an int type is more than enough. If uid can be recycled, 8-byte should ok. So I think there is a lot of optimization space.
For example:
bool isEqual(const char *uid1, const char *uid2) {
return strcmp(uid1, uid2) == 0;
}
If I can make uid an integer instead of a string, then I don't need to use the string comparison function.
bool isEqual(int uid1, int uid2) {
return uid1 == uid2;
}
But I don't know now that there are mature libraries that meet my needs.
So I want to ask you:
How feasible if I implement it myself?
What difficulties will I encounter?
What should I pay attention to?
Is there a library that already implements similar functions?
Worth it?
BTW, I can use C/C++/lua.
If you want a custom dedicated uid generation on a fully controlled distributed system, you have 3 possibilities:
A central system generates simply serial values and the other systems ask it for each new uid. Simple and fully deterministic, but the generator is a Single Point Of Failure
Each (logical) system receives an id and combines it with a local serial number. For example if the number of systems is beyond 32000 you could use 16 bits for the system id and 48 bits for the serial. Fully deterministic but requires an admin to give each system its id
Random. High quality random number generators that comply with crypto requirements should give you pseudo uid with a low probability of collision. But it is only probabilistic so a collision is still possible.
Point to pay attention to:
race conditions. If more than one process can be client for a generator, you must ensure that the uid generation is correctly synchronized
uid recycling. If the whole system must be designed to live long enough to exhaust a serial generator, you will have to keep somewhere the list of still existing entities and their uid
for the probabilistic solution, the risk of collision is proportional to the maximum number of simultaneous entities. You should carefully evaluates that probability and evaluates whether the risk can be accepted.
Are such solutions already implemented?
Yes, in database systems that allow automatic id generation.
Worth it?
Only you can say...
We have a tiny, secure, unique string ID generator for Python, which allows you to reduce ID length (but increase collisions probability), you can pass the length as an argument. To use in python env :
pip install nanoid
from nanoid import generate
generate(size=10) => u'p1yS9T21Bf'
To check how the ID's are generated an their collision probablity for a given length visit https://zelark.github.io/nano-id-cc/
Refer: https://pypi.org/project/nanoid/
for example if a certain block requires certain 5 leading zeros then can't we write a 32 byte random hash which has 5 leading zeroes like
00000C66DA510B7C524F7EF33279BCA641E2E8BF94B6B15AC6343CD2B706F673
or
00000C66DA510B7C524F7EF33279BCA641E2E8BF94B6B15AC6343CD2ASDFERTY
Also, if i am designing my own blockchain,then will choosing any random number without hashing make a difference in security of the blockchain?
You can't choose the hash of a blockchain block. Each block has some data (including the hash of the previous block), and then a "nonce", and then a cryptographic hash of the whole thing. One of the essential design properties of a cryptographic hash is that nobody knows how to choose the input to make the output come out a particular value.
What a blockchain miner does all day is compute HASH(prev_hash || new data || 1), HASH(prev_hash || new data || 2), HASH(prev_hash || data || 3), ... until they reach a number that makes the hash come out with the required number of leading zeroes. That's the work that they are proving they have done. And then they publish the block, with its nonce and hash, and it takes only a trivial amount of work by comparison to verify that HASH(prev_hash || new data || n) has the required number of leading zeroes, so the block is accepted.
Proof of work is not a mandatory feature of a blockchain, and in fact it would be really nice if we could figure out a good alternative, because proof of work is what makes Bitcoin consume as much electricity as the entire country of Sweden or whatever it's up to these days. A blockchain is just a sequence of blocks of data, chained together with cryptographic hashes and signatures. What proof-of-work does - what including the "hash must have so many leading zeroes" rule does - is make it difficult for someone to control which miner will successfully mine the next block, and that is argued to mean "no one individual can force the distributed system to accept their next block instead of someone else's."
If some of the assertions in the previous paragraph seem a bit, um, shaky to you, you are absolutely correct. That is why cryptocurrency is still a field of active research rather than something everyone uses all the time.
I want to modify smart contract template, add a function such that it will sends back certain amount of ether after crowdsale ends. The problem is, I don't quite understand how smart contract works, do they constantly get called even after ICO ends?
Also, can I keep track of every transaction that happens to my token, so that I will know who owns my token after my tokens appears on exchanges and people start to trade them? i.e. I need to know who currently hold my tokens and their wallet address. Can anyone shed some light on me??
It's a lot of question. I will try to answer with topics below.
1 - "modify smart contract": Once you deployed in the Blockchain (true blockchain, not test-net), you can't not modify your contract. You just can kill the old smart contract and build a new one.
2 - "do they constantly get called even after ICO ends" - Algorithm of ICO and the ICO in self are two different things, the algorithm only stop to work if you use (and activate) the suicide function.
3 - "can I keep track of every transaction that happens to my token" - You track just the transactions that happens inside your smart contract, that it is pretty enough if you use validations
4 - "I need to know who currently hold my tokens and their wallet address" - Use the variable mapping(address=>uint) to control the wallets that are owners of your tokens