Blind Auctions

The solidity docs have one way to make blind auctions: everybody submits a hash of their bid, and when the auction's over the bidders reveal the preimages of their hashes to show their bids.

But a blind auction doesn't really need to reveal all the bids. Everybody can just privately send their bids to the auctioneer. The auctioneer's incentive is to publish the highest bid, which is exactly what we want.

So everybody starts out by putting up a deposit, sends their signed messages to the auctioneer, and when the time's up the auctioneer picks a bid to post to the contract, which verifies the bidder's signature and pays the auctioneer.

The Solidity code to verify a signature is pretty simple:

address bidder = ecrecover(sha3(bidvalue), v, r, s);

You can put as many items as you want in the inner section (where bidvalue is), delimited by commas. Take the hash of that, and pass into ecrecover along with v, r, and s, which together make up the digital signature. Then if the signature is valid, ecrecover returns the address that made it.

The whole contract is only about a page:

contract BlindAuction {
    address public owner;
    bool public finalized;
    uint public lastBiddingBlock;
    uint public lastFinalizeBlock;
    mapping(address => uint256) public deposits;

    modifier deposit() {
        deposits[msg.sender] += msg.value;
        _
    }

    event AuctionEnded(address winner, uint amount);

    function BlindAuction (uint lastbidblock, 
                           uint finalblock) deposit {
        owner = msg.sender;
        lastBiddingBlock = lastbidblock;
        lastFinalizeBlock = finalblock;
    }

    function() deposit { }

    function finalizeAuction(uint bidvalue, 
                             uint8 v, bytes32 r, bytes32 s) deposit {
        if (msg.sender != owner
           || finalized 
           || biddingOpen() 
           || auctionExpired()) throw;

        address bidder = ecrecover(sha3(bidvalue), v, r, s);
        if (bidvalue > deposits[bidder]) return;

        finalized = true;
        deposits[bidder] -= bidvalue;
        AuctionEnded(bidder, bidvalue);
        if (!owner.call.value(bidvalue)()) throw;
    }

    function claimDeposit() deposit {
        if (finalized || auctionExpired()) {
            uint256 amount = deposits[msg.sender];
            deposits[msg.sender] = 0;
            if (!msg.sender.call.value(amount)()) throw;
        }
    }

    function biddingOpen() private returns(bool) {
        return block.number <= lastBiddingBlock; 
    }

    function auctionExpired() private returns(bool) {
        return block.number > lastFinalizeBlock;
    }
}

Signing data with the javascript API just requires a line of code:

web3.eth.sign(address, dataToSign);

This gives you a string containing v,r,s which you can send to the auctioneer, who parses it out as documented here. The signing address has to be unlocked, but since you're sending the signature off-chain anyway, you can do it from an offline computer.