mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-08 22:28:12 -05:00
158 lines
4.7 KiB
Plaintext
158 lines
4.7 KiB
Plaintext
k = 13;
|
|
field = "pallas";
|
|
|
|
constant "ConsensusProposal_V1" {
|
|
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,
|
|
}
|
|
|
|
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);
|
|
|
|
# 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.
|
|
}
|