From db3f3af6d1523600e2425930815657acd249149c Mon Sep 17 00:00:00 2001 From: parazyd Date: Wed, 7 Jun 2023 18:02:23 +0200 Subject: [PATCH] contract/money: Enforce input spend_hook is zero for StakeV1. --- src/contract/consensus/tests/harness.rs | 6 ++++-- src/contract/money/proof/burn_v1.zk | 2 -- src/contract/money/src/client/stake_v1.rs | 2 ++ src/contract/money/src/entrypoint/stake_v1.rs | 14 +++++++------- src/contract/money/src/model.rs | 4 ++++ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/contract/consensus/tests/harness.rs b/src/contract/consensus/tests/harness.rs index 93aed5656..6cde8cb00 100644 --- a/src/contract/consensus/tests/harness.rs +++ b/src/contract/consensus/tests/harness.rs @@ -443,6 +443,7 @@ impl ConsensusTestHarness { burn_pk: burn_pk.clone(), } .build()?; + let ( money_stake_params, money_stake_proofs, @@ -466,6 +467,7 @@ impl ConsensusTestHarness { mint_pk: mint_pk.clone(), } .build()?; + let (consensus_stake_params, consensus_stake_proofs, consensus_stake_secret_key) = ( consensus_stake_call_debris.params, consensus_stake_call_debris.proofs, @@ -491,10 +493,10 @@ impl ConsensusTestHarness { // Calculate transaction sizes let encoded: Vec = serialize(&stake_tx); - let size = ::std::mem::size_of_val(&*encoded); + let size = std::mem::size_of_val(&*encoded); tx_action_benchmark.sizes.push(size); let base58 = bs58::encode(&encoded).into_string(); - let size = ::std::mem::size_of_val(&*base58); + let size = std::mem::size_of_val(&*base58); tx_action_benchmark.broadcasted_sizes.push(size); Ok((stake_tx, consensus_stake_params, consensus_stake_secret_key)) diff --git a/src/contract/money/proof/burn_v1.zk b/src/contract/money/proof/burn_v1.zk index defddaf27..1afda3d87 100644 --- a/src/contract/money/proof/burn_v1.zk +++ b/src/contract/money/proof/burn_v1.zk @@ -38,8 +38,6 @@ circuit "Burn_V1" { nullifier = poseidon_hash(secret, serial); constrain_instance(nullifier); - # TODO: verify if value must be > 0 and add corresponding opcode - # Pedersen commitment for coin's value vcv = ec_mul_short(value, VALUE_COMMIT_VALUE); vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM); diff --git a/src/contract/money/src/client/stake_v1.rs b/src/contract/money/src/client/stake_v1.rs index b0542919e..2bb3255e7 100644 --- a/src/contract/money/src/client/stake_v1.rs +++ b/src/contract/money/src/client/stake_v1.rs @@ -116,10 +116,12 @@ impl MoneyStakeCallBuilder { }; debug!("Finished building input"); + // Create new random blinds and an ephemeral signature key let value_blind = pallas::Scalar::random(&mut OsRng); let token_blind = pallas::Scalar::random(&mut OsRng); let signature_secret = SecretKey::random(&mut OsRng); let user_data_blind = pallas::Base::random(&mut OsRng); + info!("Creating stake burn proof for input"); let (proof, public_inputs) = create_stake_burn_proof( &self.burn_zkbin, diff --git a/src/contract/money/src/entrypoint/stake_v1.rs b/src/contract/money/src/entrypoint/stake_v1.rs index 74a33cc92..6ca308a32 100644 --- a/src/contract/money/src/entrypoint/stake_v1.rs +++ b/src/contract/money/src/entrypoint/stake_v1.rs @@ -104,6 +104,12 @@ pub(crate) fn money_stake_process_instruction_v1( msg!("[MoneyStakeV1] Validating anonymous input"); let input = ¶ms.input; + // Spend hook should be zero so there's no protocol holding the tokens back. + if input.spend_hook != pallas::Base::ZERO { + msg!("[MoneyStakeV1] Error: Input has a non-zero spend hook set"); + return Err(MoneyError::SpendHookNonZero.into()) + } + // Only native token can be staked if input.token_commit != pedersen_commitment_base(DARK_TOKEN_ID.inner(), params.token_blind) { msg!("[MoneyStakeV1] Error: Input used non-native token"); @@ -130,19 +136,13 @@ pub(crate) fn money_stake_process_instruction_v1( return Err(MoneyError::SpendHookOutOfBounds.into()) } + // Verify next call corresponds to Consensus::StakeV1 (0x01) let next = &calls[next_call_idx as usize]; if next.contract_id.inner() != CONSENSUS_CONTRACT_ID.inner() { msg!("[MoneyStakeV1] Error: Next contract call is not consensus contract"); return Err(MoneyError::StakeNextCallNotConsensusContract.into()) } - // If spend hook is set, check its correctness - if input.spend_hook != pallas::Base::ZERO && next.contract_id.inner() != input.spend_hook { - msg!("[MoneyStakeV1] Error: Invoking contract call does not match spend hook in input"); - return Err(MoneyError::SpendHookMismatch.into()) - } - - // Verify next call corresponds to Consensus::StakeV1 (0x01) if next.data[0] != 0x01 { msg!("[MoneyStakeV1] Error: Next call function mismatch"); return Err(MoneyError::NextCallFunctionMissmatch.into()) diff --git a/src/contract/money/src/model.rs b/src/contract/money/src/model.rs index 0532b7988..761ae25e0 100644 --- a/src/contract/money/src/model.rs +++ b/src/contract/money/src/model.rs @@ -199,12 +199,14 @@ pub struct MoneyTokenFreezeUpdateV1 { /// Parameters for `Money::Stake` #[derive(Clone, Debug, SerialEncodable, SerialDecodable)] +// ANCHOR: MoneyStakeParams pub struct MoneyStakeParamsV1 { /// Blinding factor for `token_id` pub token_blind: pallas::Scalar, /// Anonymous input pub input: Input, } +// ANCHOR_END: MoneyStakeParams /// State update for `Money::Stake` #[derive(Clone, Debug, SerialEncodable, SerialDecodable)] @@ -239,12 +241,14 @@ pub struct MoneyUnstakeUpdateV1 { /// Parameters for `Consensus::Stake` #[derive(Clone, Debug, SerialEncodable, SerialDecodable)] +// ANCHOR: ConsensusStakeParams pub struct ConsensusStakeParamsV1 { /// Burnt token revealed info pub input: ConsensusInput, /// Anonymous output pub output: ConsensusOutput, } +// ANCHOR_END: ConsensusStakeParams /// State update for `Consensus::Stake` #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]