Show HN: Simple Zero-Knowledge Proof Treasure Hunt Game
zk-treasure-hunt.glitch.me
zk-treasure-hunt.glitch.me
How is the proof different than a signed message saying "This person has found the treasure"? With the private key derived from the coordinates?
Anyway, I'm off to read more about ZK proofs in hopes of making the above sound silly to me.
The idea in ZKP is to prove you know a value without revealing the value itself.
The main issue is that the circuit is simply hashing the coordinates and the resulting hash is being used to identify the treasures. So it is already fairly similar to the scenario you describe, but in an ideal ZK system it would not even reveal a hash of the coordinates, only verifiable knowledge of them.
For example, I _think_ it might be closer to true ZK if I had hardcoded an equality check with exactly (5, 10) coordinates into the ZK circuit, rather than using hashes to support a variety of coordinates (but then it wouldn’t be as general purpose). Perhaps there’s another better way though!
I wonder if there could be a mechanism for cryptographically incorporating an owner's identification into the ZKP so that I could prove that it was stolen in the above scenario? The ZKP would need to remain publicly usable so that others can verify that it's a valid proof without me, but some aspect of it would be unlockable only by my private key so that I can demonstrate that I hold said key. Does such a mechanism exist?
Sign the puzzle solution with your private key. Check signature inside the circuit. This obviously can't be applied to this particular game since it has a circuit that does not employ such measures. Alternatively, if used snark is recursive - create a new circuit that will both validate original proof and check the signature.
See my other comment on how it can be done.
You are describing attribution problem. "Solution to the puzzle is no longer a secret, it is a public knowledge. Who was the original finder?". This problem is not really concerned with the proof - there is nothing more to hide, milk has been spilled.
GP is speaking about a different problem. Thief is not stealing the secret - they are stealing the proof that secret exists. In GP's scenario thief hacks GP's machine - which is not necessary, since GP is likely to show the proof to the world himself.
> That means if someone snoops my machine and tries to use my proof to claim that they know the answer, I can spot it as a stolen proof. However, without revealing the treasure, I wouldn't be able to prove that they stole it, because it is equally possible that I stole it from them.
And I was specifically addressing the situation when GP has made proof public. In such scenario thief can point the finger at the proof and claim that they have produced it. Solution described by me prevents thief from doing it, since proof will contain a public key from a keypair thief does not possess.
Here is other poster, presenting the solution I spoke of in a clearer way: https://news.ycombinator.com/item?id=30094271
Not at all, though perhaps my choice of "42" was poor as that seems to be an actual answer to one of the examples used here. "42" was meant as a dummy proof of knowledge value, not the secret value. My bad, should have picked something more obvious.
> GP is speaking about a different problem. Thief is not stealing the secret - they are stealing the proof that secret exists. In GP's scenario thief hacks GP's machine - which is not necessary, since GP is likely to show the proof to the world himself.
Yes, this is the scenario I'm exclusively referring to.
> And I was specifically addressing the situation when GP has made proof public. In such scenario thief can point the finger at the proof and claim that they have produced it. Solution described by me prevents thief from doing it, since proof will contain a public key from a keypair thief does not possess.
Your solution gives proof the person claiming to have found the proof signed their copy of the proof before the time it was shared, it doesn't prevent a 2nd person from taking the ZKP that was signed, making a new copy of it's value (not signature history), and signing it as an original signed ZK proof and claiming to have found it even earlier. The only ways I know of to detect such forgery of an original signed document occurred all involve interactivity (which makes the problem trivial).
> Here is other poster, presenting the solution I spoke of in a clearer way: https://news.ycombinator.com/item?id=30094271
Embedding the user's public key in the ZKP process is also an interactive ZKP method, as above interactive verifications are trivial and there are many ways. The example site here uses non-interactive zero-knowledge proofs via zk-SNARK and that's where the open question left in my original comment lay.
1) secret (provided as a hidden input) is correct a solution to the puzzle
2) signature that signs the secret is correct (signature is provided as a hidden input)
3) signature corresponds to a public key (which is provided as a public input)
You don't need blockchain or interaction for that. You just provide the proof and you are done. As long as other people are not able to steal the secret and your private key - world knows that you are the only holder of the secret.
1) pepesza signs the ZKP "42424242" as the correct solution to the problem in 2022
2) pepesza's signature is correct
3) pepesza's signature corresponds to a public key
4) zamadatix see's pepesza's signed ZKP value and creates a signs it as a "new" ZKP value "42424242" as the correct solution to the problem and dates it as 2021
5) zamadatix's signature is correct
6) zamadatix's signature corresponds to a public key
7) nobody can tell whether pepesza's or zamadatix's signed version of the solution actually came first without interaction, just that each claims to have signed it at the specified times.
How do you work around 7)? Alternatively if the signature instead hides the actual value of the ZKP:
1) pepesza signs the ZKP "424242" in a way that hides what that value is or otherwise prevents it from being read without further interaction.
2) pepesza's signature is correct
3) pepesza's signature corresponds to a public key
4) nobody can verify what pepesza has signed is actually a valid ZKP as they can't read the value to check and they can't interact with pepesza or they are back to an interactive ZKP
In the first scenario you haven't proven you generated it first without interaction you've just proven you signed that you claimed to have generated it first. In the second scenario you have broken the ability for anyone to validate you have an answer as they can't read your ZKP value. If you wait for someone to challenge you and then show them that's an interaction.
Is there a way I'm missing that avoids 7) in scenario 1 or 4) in scenario 2 or an alternative scenario completely?
2) Signature = sign("42424242", privk_pepesza)
3) Witness = Circuit("42424242", Signature, pubk_pepesza). `Circuit` program will validate things I've mentioned. a) is 42424242 a correct solution to the puzzle? b) is signature correct for "42424242" as msg and pubk_pepesza as signer? It will return a computation trace - the Witness.
4) Proof = Prove(Witness). This `Prove` program is specific to a zksnark flavor that is being used. Some flavors will produce Proof of constant size.
Now pepesza sends the Proof and pubk_pepesza to zamadatix. Zamadatix runs:
Result = Validate(Proof, pubk_pepesza). If Result is true, both a) and b) are correct. This allows zamadatix to learn if pepesza actually has a solution to the puzzle. Note that Validate(Proof, pubk_zamadatix) will return false.
`Validate` is the program which can be automatically compiled from the Circuit (and things that are dependent on the flavor of zksnarks used).
The whole thing revolves around two properties of zksnarks. First - they allow to prove any(*) computation. Second - they allow to use so-called hidden inputs. In example above `pubk_pepesza` is the only public input. "42424242" and Signature are both hidden inputs and don't have to be revealed. Thus Zamadatix can create a Proof' that will result in true = Validate(Proof', pukb_zamadatix), but that would require an independent discovery of "42424242" string. Or a hack of pepesza's machine.
I know where something is on the grid, check these coordinates, and if it's there, give me a yellow hat...that is easy. If I see you have a yellow hat, I know that you know where the thing is. If I could prove that without disclosing the actual coordinates, that seems more zero knowledge to me. An example might be if you overlay a layer on the infinite plane, blacked out all, on the transparent layer, save a one by one square, and aligned it to the spot that had the easy emoji. Thereby, I prove to you I know where the easy emoji is, without giving any info regarding where it sits in the plane.
However, this isn't my field - just my thoughts.
This particular system seems to function like an IDP. Where, upon authentication and token is issued, and the 3rd party checks the token's validity. I'm not sure that is the same as zero-knowledge.
I suppose the system itself acts as a “third party” but at no stage does it require you to share the coordinates with one another, hence zero knowledge. :)
Does that make sense?
totally - and unironically. there is a lot to explore within the space of using zk proofs to mitigate sybil attacks, vote buying and botting in terms of governance tokens, NFT auctions and the like.
also the benefit of decentralization and true verifiability which this demo does not offer.
Regardless of that, great work!
A contrived example is an NFT drop that only allows you to claim 1 token per identity proof.
[1] - https://blog.cloudflare.com/introducing-zero-knowledge-proof...
proof:
{"proof":{"A":["1867600411780067514172598894560508538153359060380045576693586005748057954966","2169620374930453391614857867828473542574014121006630399026967709955925850380","1"],"B":["19528498564528468902521634480986489044663227437233934360035138487189177722814","706337827303094147746432169922700503982765234262612631196531687654713865722","1"],"C":["3726874825357289054925101646028211344121805780590499285615367952100310015198","16413790865300145964228939489264611981079279422219583850941964454619012987205","1"],"Z":["13348398295372116628737687800239385003236584392082957129655537090979023752552","21858938086065692615790404191021275401630119897894808135127612791495958708375","1"],"T1":["14360876145883521049062480571414414707162979629186454824314165195068098843755","7690383252743723537382002605037505508108694574090623371839489928167967159302","1"],"T2":["171526585437306849736171820938322340084660417215376900416315101905819784325","14860073408830920977059163351151904508851804307761461334115941048614121404124","1"],"T3":["1545121168750639889943334802450434695241204658831402130294781806168831416544","3552441256981354095031652913768122490293154222496855043326406989226641931070","1"],"eval_a":"11024792588659243456083103589833329966520500410691012025757085783760664829419","eval_b":"8139322387519291544452196793779464185899888022676212695935483571119961089263","eval_c":"2759381562617869781993539883850313928775692869004537050116210023174425255732","eval_s1":"3982161546082334136949334514760679925162813832987926352276128359736663202279","eval_s2":"13722404104721347388598646963457682656505421852782227871567200092865223175205","eval_zw":"11818614898752314321908019464035292475883958508517334670201070690246297959919","eval_r":"351033371214975959271810948327526637663211703371176137228232410629160426468","Wxi":["2849642276594154825911327435597652863159285743523681959629445273984338402763","17443880865908727420293433216572018364053739032965083704472720153118177741102","1"],"Wxiw":["10956474329499098723358633860519149253944380573151016916071333176886419683119","10706455989148992485159392381934694626464450509616938982009682610544795496695","1"],"protocol":"plonk","curve":"bn128"},"publicSignals":["14870881943777737729426810002848629979047457360865816386884132744016829330171","5"]}> you can Download the JSON Proof file, and share that publicly. It does not reveal any information of the coordinates you discovered.
But it is not at all clear that the proof does not reveal any information of the coordinates you discovered.
Similarly, it is also unclear that the JSON actually proves that you found the treasure. For example, there could be a specific string in the JSON that the program is checking
It is a cool example of coding, but not of zero knowledge proof in my opinion
The first doubt could be eliminated by an expert investigating the source code. The second doubt is more interesting to me. I wonder how that one could be dispelled.
In a more ideal scenario the code and prover/verifier would all be running in a decentralized fashion (see zk-evms and StarkNet for example).
You could also remix the demo and choose your own hashes for each emoji (see console when searching for coordinates to get its hash), and I could then be the one guessing your secret coordinates.
The demo runs locally by the way (no server needed).
{"proof":{"A":["528798437822554000995419106371609997575204115155385613032964921571940434242","19392573634889951777626956703843672538432944451899193682888548724342864529439","1"],"B":["9404113332953961826669890892917492905548480923188557301925639484569997434683","9355892340149400743721747317697733520039414623109138623712480516150240861752","1"],"C":["17025592921218423293803353276509975639327431231998740961079522035785553770278","17423498421731198093306578395594227183404340359018343837062584916083018536139","1"],"Z":["4679204973154686221676226117309749274108042290803986293348834038552965610694","18495471997097378260571021759032113343347720768624816790096532135583194497500","1"],"T1":["9867739328482857556240082341319546495849614236722730250625116628272791849277","2868165447457132393649370134790411696593144462382351418948962174508512798119","1"],"T2":["17087199959171424064564733158000941043006524389450810193258931251521734973371","2911105227677439634206272144083822945188790339567179520353606559518569996983","1"],"T3":["7129249599766093445028171268444907082411743186316411948288132376306904700379","2606039354317638260688803298171035577991543816558705808789024740126554704610","1"],"eval_a":"6895260220541269063962193341698926909365015746291078556123010150492168710344","eval_b":"8068725092477246053082827431610612461501706876500056081310697342029389110657","eval_c":"2704512929705984824776357863771653984806802643988862884038528594470902574120","eval_s1":"4794695569847439900751267112418103273161829262476159763959027953943371223323","eval_s2":"2163495885363626668152176373764360379814151330932793558189464412748989368897","eval_zw":"18806651421491306865145175336745334163344143620725244191448339490901611643578","eval_r":"17436641083417465197082211434092476275687970780131379758738973376030688767532","Wxi":["4431163539146773180222688732344240958561729429168725197361826098528123452180","10531431324455376227237108983493044130410098406199107820103575253972171316343","1"],"Wxiw":["5408442091202782791687007786548171585846105046857466808022018453657877169978","3593469123965015521385191034691943033447797110216175041703174577320301325259","1"],"protocol":"plonk","curve":"bn128"},"publicSignals":["14870881943777737729426810002848629979047457360865816386884132744016829330171","5"]}