|
|
@@ -2,156 +2,156 @@ k = 13;
|
|
|
field = "pallas";
|
|
|
|
|
|
constant "ConsensusProposal_V1" {
|
|
|
- EcFixedPointShort VALUE_COMMIT_VALUE,
|
|
|
- EcFixedPoint VALUE_COMMIT_RANDOM,
|
|
|
- EcFixedPointBase NULLIFIER_K,
|
|
|
+ EcFixedPointShort VALUE_COMMIT_VALUE,
|
|
|
+ EcFixedPoint VALUE_COMMIT_RANDOM,
|
|
|
+ EcFixedPointBase NULLIFIER_K,
|
|
|
}
|
|
|
|
|
|
witness "ConsensusProposal_V1" {
|
|
|
- # Burnt coin secret key
|
|
|
- Base input_secret_key,
|
|
|
- # Unique serial number corresponding to the burnt coin
|
|
|
- Base input_serial,
|
|
|
- # The value of the burnt coin
|
|
|
- Base input_value,
|
|
|
- # The epoch the burnt coin was minted on
|
|
|
- Base epoch,
|
|
|
- # The reward value
|
|
|
- Base reward,
|
|
|
- # Random blinding factor for the value commitment
|
|
|
- Scalar input_value_blind,
|
|
|
- # Leaf position of the coin in the Merkle tree of coins
|
|
|
- Uint32 leaf_pos,
|
|
|
- # Merkle path to the coin
|
|
|
- MerklePath path,
|
|
|
- # Random blinding factor for the value commitment of the new coin
|
|
|
- Scalar output_value_blind,
|
|
|
- # Election seed y
|
|
|
- Base mu_y,
|
|
|
- # Election seed rho
|
|
|
- Base mu_rho,
|
|
|
- # Sigma1
|
|
|
- Base sigma1,
|
|
|
- # Sigma2
|
|
|
- Base sigma2,
|
|
|
- # Lottery headstart
|
|
|
- Base headstart,
|
|
|
+ # Burnt coin secret key
|
|
|
+ Base input_secret_key,
|
|
|
+ # Unique serial number corresponding to the burnt coin
|
|
|
+ Base input_serial,
|
|
|
+ # The value of the burnt coin
|
|
|
+ Base input_value,
|
|
|
+ # The epoch the burnt coin was minted on
|
|
|
+ Base epoch,
|
|
|
+ # The reward value
|
|
|
+ Base reward,
|
|
|
+ # Random blinding factor for the value commitment
|
|
|
+ Scalar input_value_blind,
|
|
|
+ # Leaf position of the coin in the Merkle tree of coins
|
|
|
+ Uint32 leaf_pos,
|
|
|
+ # Merkle path to the coin
|
|
|
+ MerklePath path,
|
|
|
+ # Random blinding factor for the value commitment of the new coin
|
|
|
+ Scalar output_value_blind,
|
|
|
+ # Election seed y
|
|
|
+ Base mu_y,
|
|
|
+ # Election seed rho
|
|
|
+ Base mu_rho,
|
|
|
+ # Sigma1
|
|
|
+ Base sigma1,
|
|
|
+ # Sigma2
|
|
|
+ Base sigma2,
|
|
|
+ # Lottery headstart
|
|
|
+ Base headstart,
|
|
|
}
|
|
|
|
|
|
circuit "ConsensusProposal_V1" {
|
|
|
- # Witnessed constants
|
|
|
- ZERO = witness_base(0);
|
|
|
- SERIAL_PREFIX = witness_base(2);
|
|
|
- SEED_PREFIX = witness_base(3);
|
|
|
- SECRET_PREFIX = witness_base(4);
|
|
|
-
|
|
|
- # =============
|
|
|
- # Burn old coin
|
|
|
- # =============
|
|
|
-
|
|
|
- # Poseidon hash of the nullifier
|
|
|
- nullifier = poseidon_hash(input_secret_key, input_serial);
|
|
|
- constrain_instance(nullifier);
|
|
|
-
|
|
|
- # Constrain the epoch this coin was minted on.
|
|
|
- # We use this as our timelock mechanism.
|
|
|
- constrain_instance(epoch);
|
|
|
-
|
|
|
- # We derive the coin's public key for the signature and
|
|
|
- # VRF proof verification and constrain its coordinates:
|
|
|
- input_pub = ec_mul_base(input_secret_key, NULLIFIER_K);
|
|
|
- pub_x = ec_get_x(input_pub);
|
|
|
- pub_y = ec_get_y(input_pub);
|
|
|
- constrain_instance(pub_x);
|
|
|
- constrain_instance(pub_y);
|
|
|
-
|
|
|
- # Construct the burned coin
|
|
|
- C = poseidon_hash(
|
|
|
- pub_x,
|
|
|
- pub_y,
|
|
|
- input_value,
|
|
|
- epoch,
|
|
|
- input_serial,
|
|
|
- );
|
|
|
-
|
|
|
- # Merkle inclusion proof
|
|
|
- root = merkle_root(leaf_pos, path, C);
|
|
|
- constrain_instance(root);
|
|
|
-
|
|
|
- # Pedersen commitment for burned coin's value
|
|
|
- vcv = ec_mul_short(input_value, VALUE_COMMIT_VALUE);
|
|
|
- vcr = ec_mul(input_value_blind, VALUE_COMMIT_RANDOM);
|
|
|
- value_commit = ec_add(vcv, vcr);
|
|
|
- # Since value_commit is a curve point, we fetch its coordinates
|
|
|
- # and constrain them:
|
|
|
- constrain_instance(ec_get_x(value_commit));
|
|
|
- constrain_instance(ec_get_y(value_commit));
|
|
|
-
|
|
|
- # =============
|
|
|
- # Mint new coin
|
|
|
- # =============
|
|
|
-
|
|
|
- # Constrain reward value
|
|
|
- constrain_instance(reward);
|
|
|
-
|
|
|
- # Pedersen commitment for new coin's value (old value + reward)
|
|
|
- output_value = base_add(input_value, reward);
|
|
|
- nvcv = ec_mul_short(output_value, VALUE_COMMIT_VALUE);
|
|
|
- nvcr = ec_mul(output_value_blind, VALUE_COMMIT_RANDOM);
|
|
|
- output_value_commit = ec_add(nvcv, nvcr);
|
|
|
- # Since the new value commit is also a curve point, we'll do the same
|
|
|
- # coordinate dance:
|
|
|
- constrain_instance(ec_get_x(output_value_commit));
|
|
|
- constrain_instance(ec_get_y(output_value_commit));
|
|
|
-
|
|
|
- # The serial of the new coin is derived from the old coin
|
|
|
- output_serial = poseidon_hash(SERIAL_PREFIX, input_secret_key, input_serial);
|
|
|
-
|
|
|
- # The secret key of the new coin is derived from old coin
|
|
|
- output_secret_key = poseidon_hash(SECRET_PREFIX, input_secret_key);
|
|
|
- output_pub = ec_mul_base(output_secret_key, NULLIFIER_K);
|
|
|
- output_pub_x = ec_get_x(output_pub);
|
|
|
- output_pub_y = ec_get_y(output_pub);
|
|
|
+ # Witnessed constants
|
|
|
+ ZERO = witness_base(0);
|
|
|
+ SERIAL_PREFIX = witness_base(2);
|
|
|
+ SEED_PREFIX = witness_base(3);
|
|
|
+ SECRET_PREFIX = witness_base(4);
|
|
|
+
|
|
|
+ # =============
|
|
|
+ # Burn old coin
|
|
|
+ # =============
|
|
|
+
|
|
|
+ # Poseidon hash of the nullifier
|
|
|
+ nullifier = poseidon_hash(input_secret_key, input_serial);
|
|
|
+ constrain_instance(nullifier);
|
|
|
+
|
|
|
+ # Constrain the epoch this coin was minted on.
|
|
|
+ # We use this as our timelock mechanism.
|
|
|
+ constrain_instance(epoch);
|
|
|
+
|
|
|
+ # We derive the coin's public key for the signature and
|
|
|
+ # VRF proof verification and constrain its coordinates:
|
|
|
+ input_pub = ec_mul_base(input_secret_key, NULLIFIER_K);
|
|
|
+ pub_x = ec_get_x(input_pub);
|
|
|
+ pub_y = ec_get_y(input_pub);
|
|
|
+ constrain_instance(pub_x);
|
|
|
+ constrain_instance(pub_y);
|
|
|
+
|
|
|
+ # Construct the burned coin
|
|
|
+ C = poseidon_hash(
|
|
|
+ pub_x,
|
|
|
+ pub_y,
|
|
|
+ input_value,
|
|
|
+ epoch,
|
|
|
+ input_serial,
|
|
|
+ );
|
|
|
+
|
|
|
+ # Merkle inclusion proof
|
|
|
+ root = merkle_root(leaf_pos, path, C);
|
|
|
+ constrain_instance(root);
|
|
|
+
|
|
|
+ # Pedersen commitment for burned coin's value
|
|
|
+ vcv = ec_mul_short(input_value, VALUE_COMMIT_VALUE);
|
|
|
+ vcr = ec_mul(input_value_blind, VALUE_COMMIT_RANDOM);
|
|
|
+ value_commit = ec_add(vcv, vcr);
|
|
|
+ # Since value_commit is a curve point, we fetch its coordinates
|
|
|
+ # and constrain them:
|
|
|
+ constrain_instance(ec_get_x(value_commit));
|
|
|
+ constrain_instance(ec_get_y(value_commit));
|
|
|
+
|
|
|
+ # =============
|
|
|
+ # Mint new coin
|
|
|
+ # =============
|
|
|
+
|
|
|
+ # Constrain reward value
|
|
|
+ constrain_instance(reward);
|
|
|
+
|
|
|
+ # Pedersen commitment for new coin's value (old value + reward)
|
|
|
+ output_value = base_add(input_value, reward);
|
|
|
+ nvcv = ec_mul_short(output_value, VALUE_COMMIT_VALUE);
|
|
|
+ nvcr = ec_mul(output_value_blind, VALUE_COMMIT_RANDOM);
|
|
|
+ output_value_commit = ec_add(nvcv, nvcr);
|
|
|
+ # Since the new value commit is also a curve point, we'll do the same
|
|
|
+ # coordinate dance:
|
|
|
+ constrain_instance(ec_get_x(output_value_commit));
|
|
|
+ constrain_instance(ec_get_y(output_value_commit));
|
|
|
+
|
|
|
+ # The serial of the new coin is derived from the old coin
|
|
|
+ output_serial = poseidon_hash(SERIAL_PREFIX, input_secret_key, input_serial);
|
|
|
+
|
|
|
+ # The secret key of the new coin is derived from old coin
|
|
|
+ output_secret_key = poseidon_hash(SECRET_PREFIX, input_secret_key);
|
|
|
+ output_pub = ec_mul_base(output_secret_key, NULLIFIER_K);
|
|
|
+ output_pub_x = ec_get_x(output_pub);
|
|
|
+ output_pub_y = ec_get_y(output_pub);
|
|
|
|
|
|
- # Poseidon hash of the new coin
|
|
|
- # In here we set the new epoch as ZERO, thus removing a
|
|
|
- # potentially existing timelock.
|
|
|
- output_coin = poseidon_hash(
|
|
|
- output_pub_x,
|
|
|
- output_pub_y,
|
|
|
- output_value,
|
|
|
- ZERO,
|
|
|
- output_serial,
|
|
|
- );
|
|
|
- constrain_instance(output_coin);
|
|
|
-
|
|
|
- # ============================
|
|
|
- # Constrain lottery parameters
|
|
|
- # ============================
|
|
|
-
|
|
|
- # Coin y, constructed with the old serial for seeding:
|
|
|
- seed = poseidon_hash(SEED_PREFIX, input_serial);
|
|
|
- y = poseidon_hash(seed, mu_y);
|
|
|
- constrain_instance(mu_y);
|
|
|
- constrain_instance(y);
|
|
|
-
|
|
|
- # Coin rho (seed):
|
|
|
- rho = poseidon_hash(seed, mu_rho);
|
|
|
- constrain_instance(mu_rho);
|
|
|
- constrain_instance(rho);
|
|
|
-
|
|
|
- # Calculate lottery target
|
|
|
- term_1 = base_mul(sigma1, input_value);
|
|
|
- term_2 = base_mul(sigma2, input_value);
|
|
|
- shifted_term_2 = base_mul(term_2, input_value);
|
|
|
- target = base_add(term_1, shifted_term_2);
|
|
|
- shifted_target = base_add(target, headstart);
|
|
|
- constrain_instance(sigma1);
|
|
|
- constrain_instance(sigma2);
|
|
|
- constrain_instance(headstart);
|
|
|
-
|
|
|
- # Play lottery
|
|
|
- less_than_strict(y, shifted_target);
|
|
|
-
|
|
|
- # At this point we've enforced all of our public inputs.
|
|
|
+ # Poseidon hash of the new coin
|
|
|
+ # In here we set the new epoch as ZERO, thus removing a
|
|
|
+ # potentially existing timelock.
|
|
|
+ output_coin = poseidon_hash(
|
|
|
+ output_pub_x,
|
|
|
+ output_pub_y,
|
|
|
+ output_value,
|
|
|
+ ZERO,
|
|
|
+ output_serial,
|
|
|
+ );
|
|
|
+ constrain_instance(output_coin);
|
|
|
+
|
|
|
+ # ============================
|
|
|
+ # Constrain lottery parameters
|
|
|
+ # ============================
|
|
|
+
|
|
|
+ # Coin y, constructed with the old serial for seeding:
|
|
|
+ seed = poseidon_hash(SEED_PREFIX, input_serial);
|
|
|
+ y = poseidon_hash(seed, mu_y);
|
|
|
+ constrain_instance(mu_y);
|
|
|
+ constrain_instance(y);
|
|
|
+
|
|
|
+ # Coin rho (seed):
|
|
|
+ rho = poseidon_hash(seed, mu_rho);
|
|
|
+ constrain_instance(mu_rho);
|
|
|
+ constrain_instance(rho);
|
|
|
+
|
|
|
+ # Calculate lottery target
|
|
|
+ term_1 = base_mul(sigma1, input_value);
|
|
|
+ term_2 = base_mul(sigma2, input_value);
|
|
|
+ shifted_term_2 = base_mul(term_2, input_value);
|
|
|
+ target = base_add(term_1, shifted_term_2);
|
|
|
+ shifted_target = base_add(target, headstart);
|
|
|
+ constrain_instance(sigma1);
|
|
|
+ constrain_instance(sigma2);
|
|
|
+ constrain_instance(headstart);
|
|
|
+
|
|
|
+ # Play lottery
|
|
|
+ less_than_strict(y, shifted_target);
|
|
|
+
|
|
|
+ # At this point we've enforced all of our public inputs.
|
|
|
}
|