Просмотр исходного кода

zkas/proofs: Add initial doc and proper source code for anonymous voting.

parazyd 4 лет назад
Родитель
Сommit
9888739171
3 измененных файлов с 68 добавлено и 2 удалено
  1. 1 0
      book/src/SUMMARY.md
  2. 50 0
      book/src/zkas/examples/voting.md
  3. 17 2
      zkas/proofs/voting.zk

+ 1 - 0
book/src/SUMMARY.md

@@ -10,3 +10,4 @@
   - [Bincode](zkas/bincode.md)
   - [Examples](zkas/examples.md)
     - [Sapling scheme](zkas/examples/sapling.md)
+    - [Anonymous voting](zkas/examples/voting.md)

+ 50 - 0
book/src/zkas/examples/voting.md

@@ -0,0 +1,50 @@
+Anonymous voting
+================
+
+Anonymous voting[^1] is a type of voting process where users can
+vote without revealing their identity, by proving they are accepted
+as valid voters.
+
+The proof enables user privacy and allows for fully anonymous voting.
+
+The starting point is a Merkle proof[^2], which efficiently proves that
+a voter's key belongs to a Merkle tree. However, using this proof alone
+would allow the organizer of a process to correlate each vote envelope
+with its voter's key on the database, so votes wouldn't be secret.
+
+## Vote proof
+
+```
+{{#include ../../../../zkas/proofs/voting.zk}}
+```
+
+Our proof consists of four main operation. First we are hashing the
+_nullifier_ using our secret key and the hashed process ID. Next,
+we derive our public key and hash it. Following, we take this hash
+and create a Merkle proof that it is indeed contained in the given
+Merkle tree. And finally, we create a _Pedersen commitment_[^3]
+for the vote choice itself.
+
+Our vector of public inputs can look like this:
+
+```
+let public_inputs = vec![
+    nullifier,
+    merkle_root,
+    *vote_coords.x(),
+    *vote_coords.y(),
+]
+```
+
+And then the Verifier uses these public inputs to verify the given
+zero-knowledge proof.
+
+[^1]: Specification taken from [vocdoni franchise proof](https://docs.vocdoni.io/architecture/protocol/anonymous-voting/zk-census-proof.html)
+
+[^2]: [Merkle tree on Wikipedia](https://en.wikipedia.org/wiki/Merkle_tree)
+
+[^3]: See section 3: _The Commitment Scheme_ of Torben Pryds Pedersen's
+    [paper on Non-Interactive and
+    Information-Theoretic Secure Verifiable Secret
+    Sharing](https://link.springer.com/content/pdf/10.1007%2F3-540-46766-1_9.pdf)
+

+ 17 - 2
zkas/proofs/voting.zk

@@ -1,4 +1,6 @@
 constant "Vote" {
+	EcFixedPoint VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
 	EcFixedPoint NULLIFIER_K,
 }
 
@@ -6,23 +8,36 @@ contract "Vote" {
 	Base process_id_0,
 	Base process_id_1,
 	Base secret_key,
-	Base vote_hash,
+	Base vote,
+	Scalar vote_blind,
 	Uint32 leaf_pos,
 	MerklePath path,
 }
 
 circuit "Vote" {
+	# Nullifier hash
 	process_id = poseidon_hash(process_id_0, process_id_1);
 	nullifier = poseidon_hash(secret_key, process_id);
 	constrain_instance(nullifier);
 
+	# Public key derivation and hashing
 	public_key = ec_mul_base(secret_key, NULLIFIER_K);
 	public_x = ec_get_x(public_key);
 	public_y = ec_get_y(public_key);
 	pk_hash = poseidon_hash(public_x, public_y);
 
+	# Merkle root
 	root = calculate_merkle_root(leaf_pos, path, pk_hash);
 	constrain_instance(root);
 
-	constrain_instance(vote_hash);
+	# Pedersen commitment for vote
+	vcv = ec_mul_short(vote, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(vote_blind, VALUE_COMMIT_RANDOM);
+	vote_commit = ec_add(vcv, vcr);
+	# Since vote_commit is a curve point, we fetch its coordinates
+	# and constrain_them:
+	vote_commit_x = ec_get_x(vote_commit);
+	vote_commit_y = ec_get_y(vote_commit);
+	constrain_instance(vote_commit_x);
+	constrain_instance(vote_commit_y);
 }