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

contract/consensus: ProposalReward to also constran new coin serial commit and validate between steps ProposalReward->ProposalMint

aggstam 3 лет назад
Родитель
Сommit
9e8d8c1ef8

+ 14 - 0
src/contract/consensus/proof/proposal_reward_v1.zk

@@ -1,6 +1,7 @@
 constant "ProposalReward_V1" {
 	EcFixedPointShort VALUE_COMMIT_VALUE,
 	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
 }
 
 witness "ProposalReward_V1" {
@@ -14,6 +15,8 @@ witness "ProposalReward_V1" {
 	Base reward,
 	# Random blinding factor for the value commitment
 	Scalar value_blind,
+	# Random blinding factor for the serial number of the new coin
+	Scalar new_serial_blind,
 	# Election seed y
 	Base mu_y,
 	# Election seed rho
@@ -29,6 +32,7 @@ witness "ProposalReward_V1" {
 circuit "ProposalReward_V1" {
 	# Constants
 	ZERO = witness_base(0);
+	SERIAL_PREFIX = witness_base(2);
 	SEED_PREFIX = witness_base(3);
 
 	# Poseidon hash of the coin nullifier
@@ -44,6 +48,16 @@ circuit "ProposalReward_V1" {
 	constrain_instance(ec_get_x(value_commit));
 	constrain_instance(ec_get_y(value_commit));
 
+	# Derive new coin serial from burnt one and constrain the pedersen commitment
+	new_serial = poseidon_hash(SERIAL_PREFIX, secret_key, serial, ZERO);
+	scv = ec_mul_base(new_serial, NULLIFIER_K);
+	scr = ec_mul(new_serial_blind, VALUE_COMMIT_RANDOM);
+	serial_commit = ec_add(scv, scr);
+	# Since serial commit is also a curve point, we'll do the same
+	# coordinate dance:
+	constrain_instance(ec_get_x(serial_commit));
+	constrain_instance(ec_get_y(serial_commit));
+
 	# Pedersen commitment for new coin's value
 	new_value = base_add(value, reward);
 	nvcv = ec_mul_short(new_value, VALUE_COMMIT_VALUE);

+ 21 - 3
src/contract/consensus/src/client/proposal_v1.rs

@@ -64,6 +64,7 @@ pub struct ConsensusProposalCallDebris {
 pub struct ConsensusProposalRewardRevealed {
     pub nullifier: Nullifier,
     pub value_commit: pallas::Point,
+    pub new_serial_commit: pallas::Point,
     pub new_value_commit: pallas::Point,
     pub mu_y: pallas::Base,
     pub y: pallas::Base,
@@ -76,6 +77,7 @@ pub struct ConsensusProposalRewardRevealed {
 impl ConsensusProposalRewardRevealed {
     pub fn to_vec(&self) -> Vec<pallas::Base> {
         let value_coords = self.value_commit.to_affine().coordinates().unwrap();
+        let new_serial_coords = self.new_serial_commit.to_affine().coordinates().unwrap();
         let new_value_coords = self.new_value_commit.to_affine().coordinates().unwrap();
 
         // NOTE: It's important to keep these in the same order
@@ -84,6 +86,8 @@ impl ConsensusProposalRewardRevealed {
             self.nullifier.inner(),
             *value_coords.x(),
             *value_coords.y(),
+            *new_serial_coords.x(),
+            *new_serial_coords.y(),
             *new_value_coords.x(),
             *new_value_coords.y(),
             self.mu_y,
@@ -265,7 +269,7 @@ impl ConsensusProposalCallBuilder {
         let stake_params = ConsensusProposalMintParamsV1 {
             input: input.clone(),
             output: output.clone(),
-            serial_commit,
+            serial_commit: serial_commit.clone(),
         };
         let stake_proofs = vec![proof];
         let stake_input = input;
@@ -281,14 +285,23 @@ impl ConsensusProposalCallBuilder {
             serial,
             value,
             value_blind,
+            serial_blind,
         )?;
 
         // We now fill this with necessary stuff
+        let new_serial_commit = serial_commit;
         let slot = self.slot_checkpoint.slot;
         let y = public_inputs.y;
         let rho = public_inputs.rho;
-        let reward_params =
-            ConsensusProposalRewardParamsV1 { unstake_input, stake_input, output, slot, y, rho };
+        let reward_params = ConsensusProposalRewardParamsV1 {
+            unstake_input,
+            stake_input,
+            output,
+            new_serial_commit,
+            slot,
+            y,
+            rho,
+        };
         let reward_proofs = vec![proof];
 
         // Now we should have all the params, zk proofs and signature secret.
@@ -314,10 +327,13 @@ pub fn create_proposal_reward_proof(
     serial: pallas::Base,
     value: u64,
     value_blind: pallas::Scalar,
+    new_serial_blind: pallas::Scalar,
 ) -> Result<(Proof, ConsensusProposalRewardRevealed)> {
     // Proof parameters
     let nullifier = Nullifier::from(poseidon_hash([secret_key, serial]));
     let value_commit = pedersen_commitment_u64(value, value_blind);
+    let new_serial = poseidon_hash([SERIAL_PREFIX, secret_key, serial, ZERO]);
+    let new_serial_commit = pedersen_commitment_base(new_serial, new_serial_blind);
     let new_value_commit = pedersen_commitment_u64(value + REWARD, value_blind);
     let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
     let seed = poseidon_hash([SEED_PREFIX, serial, ZERO]);
@@ -331,6 +347,7 @@ pub fn create_proposal_reward_proof(
     let public_inputs = ConsensusProposalRewardRevealed {
         nullifier,
         value_commit,
+        new_serial_commit,
         new_value_commit,
         mu_y,
         y,
@@ -346,6 +363,7 @@ pub fn create_proposal_reward_proof(
         Witness::Base(Value::known(pallas::Base::from(value))),
         Witness::Base(Value::known(REWARD_PALLAS)),
         Witness::Scalar(Value::known(value_blind)),
+        Witness::Scalar(Value::known(new_serial_blind)),
         Witness::Base(Value::known(mu_y)),
         Witness::Base(Value::known(mu_rho)),
         Witness::Base(Value::known(sigma1)),

+ 4 - 5
src/contract/consensus/src/entrypoint/proposal_mint_v1.rs

@@ -153,11 +153,10 @@ pub(crate) fn consensus_proposal_mint_process_instruction_v1(
     // Verify previous call input is the same as this calls StakeInput
     let previous_params: ConsensusProposalRewardParamsV1 = deserialize(&previous.data[1..])?;
     let previous_input = &previous_params.stake_input;
-    if &previous_input != &input {
-        msg!("[ConsensusProposalMintV1] Error: Previous call input mismatch");
-        return Err(MoneyError::PreviousCallInputMissmatch.into())
-    }
-    if &previous_params.output != output {
+    if &previous_input != &input ||
+        &previous_params.output != output ||
+        &previous_params.new_serial_commit != &params.serial_commit
+    {
         msg!("[ConsensusProposalMintV1] Error: Previous call input mismatch");
         return Err(MoneyError::PreviousCallInputMissmatch.into())
     }

+ 9 - 5
src/contract/consensus/src/entrypoint/proposal_reward_v1.rs

@@ -63,6 +63,9 @@ pub(crate) fn consensus_proposal_reward_get_metadata_v1(
     // Grab the pedersen commitment for the burnt value
     let value_coords = &params.unstake_input.value_commit.to_affine().coordinates().unwrap();
 
+    // Grab the pedersen commitment for the minted serial number
+    let new_serial_coords = &params.new_serial_commit.to_affine().coordinates().unwrap();
+
     // Grab the pedersen commitment for the minted value
     let new_value_coords = &params.stake_input.value_commit.to_affine().coordinates().unwrap();
 
@@ -92,6 +95,8 @@ pub(crate) fn consensus_proposal_reward_get_metadata_v1(
             nullifier.inner(),
             *value_coords.x(),
             *value_coords.y(),
+            *new_serial_coords.x(),
+            *new_serial_coords.y(),
             *new_value_coords.x(),
             *new_value_coords.y(),
             mu_y,
@@ -206,11 +211,10 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
 
     // Verify next call StakeInput is the same as this calls input
     let next_params: ConsensusProposalMintParamsV1 = deserialize(&next.data[1..])?;
-    if stake_input != &next_params.input {
-        msg!("[ConsensusProposalRewardV1] Error: Next call input mismatch");
-        return Err(MoneyError::NextCallInputMissmatch.into())
-    }
-    if output != &next_params.output {
+    if stake_input != &next_params.input ||
+        output != &next_params.output ||
+        &params.new_serial_commit != &next_params.serial_commit
+    {
         msg!("[ConsensusProposalRewardV1] Error: Next call input mismatch");
         return Err(MoneyError::NextCallInputMissmatch.into())
     }

+ 2 - 0
src/contract/consensus/src/model.rs

@@ -29,6 +29,8 @@ pub struct ConsensusProposalRewardParamsV1 {
     pub stake_input: StakeInput,
     /// Anonymous output
     pub output: Output,
+    /// Pedersen commitment for the output's serial number
+    pub new_serial_commit: pallas::Point,
     /// Rewarded slot
     pub slot: u64,
     /// Coin y