We start out with the exchange having two things. It has a set of Bitcoin addresses that it owns, each of which has some balance. It also has a set of accounts, each of which it owes some number of Bitcoin to. The objective is to prove that the exchange controls each Bitcoin address on that list and that the total of all account debts is less than the total balance of all accounts, without revealing anyone's balance to anyone else or any totals.
To do this, the exchange must first assign accounts to Bitcoin addresses such that no single address is overspent. This may require moving Bitcoins around. Now, the exchange assembles a giant merkle radix tree. From the root are inner nodes that are indexed by the Bitcoin address they link to. When you reach a Bitcoin address, the nodes contains balances, so if an address contains, say, 10 Bitcoins, the child nodes have balances that add up to no more than 10. Off the balance nodes are account nodes -- these hold the individual user accounts. Each user account node is signed with the key corresponding to the Bitcoin address.
The exchange now publishes the hash of the tip of this tree. Any user who wishes to challenge the exchange will be given the following:
Every node that leads to their account node.
Every other inner node that hangs off the address node their account node hangs off.
This doesn't tell them any totals, since they have no address nodes but the one their account is assigned to. This doesn't let them see anyone else's balance, since they only have their own account node.
They can now confirm that there is a real Bitcoin address that the exchange controls (because their account node is signed with that key) and that a portion of that balance equal to what they are owed has been uniquely assigned to them.