> Can someone explain how this works to a non-mathematician?

Sure if you're willing to let me blackbox away the worst of the complexity.

First: There exists a special execution environment where you can run a program with some inputs known to the public and other inputs that are secret and only known to you. As a result of the properties of this execution environment the output of the program comes along with a compact (constant size, regardless of the program!) proof which you can show to people which will convince them that the output really was the correct output of running that specific program with those public inputs and some secret inputs and they learn nothing about the secret inputs.

If you're willing to accept that much, the rest is simple. If not— well the math to make those proofs efficient is really N levels deep of really gnarly abstract algebra and cryptographic assumptions. I've never seen a strong explanation which is adequate for an ordinary mathematician (as opposed to one who is expert in the relevant subfields), much less Joe-HNer. If even the idea that someone can prove the validity of execution in zero knowledge seems incredible to you, before we start talking about small proofs, then maybe I can help there: I came up with a toy (not proven secure) example system for this that doesn't require more math than accepting one way functions function, and some simple statistical reasoning to follow: https://people.xiph.org/~greg/simple_verifyable_execution.tx... (I created this not as something for people to use, but because if I want people to start engineering systems that makes use of this technology I must first remove it from the realm of unbelievable magic. :))

In any case, given that we've got this magical proof producing execution environment the rest follows naturally:

To make a transaction paying to an anonymous address, I take the recipient's one time public key, a random nonce, and the value of the amount that I'm paying and hash them: OUT = H(pubkey|value|nonce). You can think of this as an 'encrypted' coin. I then have a program that checks that OUT really is the hash of the recipient's pubkey and some nonce (known only to me) and the value that its supposed to be. I run the program (which just runs the hash and an equivalence test) in the magic ZK execution environment and it gives me a proof. I stick OUT and the proof in my transaction. By virtue of the proof the network is convinced that OUT is a valid blinded coin with the correct value, even though it can't tell what the nonce/pubkey was and so it can't check for itself by repeating the computation. After accepting my transaction the network appends OUT to a merkle hash tree over all previously created anonymous outputs. I tell the recipient the nonce and value, and he can see that the newly created coin has been added to the network's collection of coins.

Later, when the recipient wants to spend that coin, he goes and extracts the log2() sized tree fragment (all the hashes along the path from the root to the coin) which can be used that coin is in the network's current hashtree. He has a program that verifies that takes this fragment and verifies that it's valid, his pubkey, and the nonce it also takes a new anonymous output (like my first program, a new pubkey nonce and value), and verifies that the values add up. He runs this program in the ZK proof environment with the pubkey that its spending and the new output as public inputs, and the hash tree fragment as a secret input... and gets a proof.

He sticks the proof in a transaction along with the new output, and signs it with the public key he just revealed. The network can now be convinced that he's spending a coin that exists (though it doesn't know which), and that it's creating a new coin (which it will add to the list) with a permissible value (though it doesn't know the value). The network then remembers the public key used, and never permits another transaction that uses the same pubkey— this prevents him from spending the same coin over and over again. No one observing can tell which coin was spent, because although they can now see the pubkey they still don't know the nonce and so they can't go testing against all the previously created coins.

Of course, to make a real system out of this you need several different programs that you can run in the ZK environment: A program to create a new anonymous coin from non-anonymous sources with known values (e.g. to let you mine coins anonymously), a program to take two anonymous coins and produce one new anonymous coin of the sum value (perhaps leaking a little value for fees), and a program to take one anonymous coin and split it into two anonymous coins. (Perhaps you might want some other variation— though in the ZKP system used for ZeroCash each distinct circuit, since they do not use a universal circuit for efficiency reasons, requires the provers to have hundreds of megs of of 'prover key' created by the trusted initialization process, so its helpful to avoid having too many different programs)

The security of all this depends on the integrity of the ZKP system. If its compromised, no privacy is lost, the succinct proofs aren't even big enough to leak the secret data... but someone who has compromised the proof system could create false proofs, spending coins that never existed.

Hopefully this makes it a bit more accessible?