Since Ethereum contracts can have their source code verified then this should be as simple as making use of an RNG to pick cards randomly from a deck. Anyone who wishes to verify that the deck is adequately shuffled can verify the contract source code.
Since generation of good randomness is addressed elsewhere this answer assumes that the card shuffling contract has access to good random numbers.
Using on-demand randomness
Producing a well shuffled deck can be done by randomly selecting cards from an unshuffled deck and building a new deck until the unshuffled deck has been depleted.
contract Deck {
uint8[52] deck;
function getRandomNumber() returns (uint) {
...;
}
function shuffle() {
uint8[52] memory unshuffled;
for (uint8 i=0; i < 52; i++) {
unshuffled[i] = i;
}
uint cardIndex;
for (i=0; i < 52; i++) {
cardIndex = getRandomNumber() % (52 - i);
deck[i] = unshuffled[cardIndex];
unshuffled[cardIndex] = unshuffled[52 - i - 1]
}
}
}
This contract represents each of the 52 cards as an integer between 0-51 inclusive. A call to the shuffle
function will populate the deck
storage variable with a 52 card deck with random ordering.
Responding to random input.
This assumes that randomness can be safely requested which is not necessarily feasible. If this is not the case and randomness must instead be sent into the contract then the following general concept should work equally well.
contract Deck {
uint8[52] deck;
function shuffle(bytes randomBytes) {
if (randomBytes.length < 52) throw;
uint8[52] memory unshuffled;
for (uint8 i=0; i < 52; i++) {
unshuffled[i] = i;
}
uint8 cardIndex;
for (i=0; i < 52; i++) {
cardIndex = uint8(randomBytes[i]) % (52 - i);
deck[i] = unshuffled[cardIndex];
unshuffled[cardIndex] = unshuffled[52 - i - 1];
}
}
}
This version of the contract requires at least 52 bytes of randomness to be included with the call to shuffle
.