contract/consensus: create serial commitment in ProposalMint and constrain it

This commit is contained in:
aggstam
2023-05-10 22:35:27 +03:00
parent 7c8dcf3010
commit bcb3b222d9
7 changed files with 98 additions and 39 deletions

View File

@@ -27,6 +27,8 @@ witness "ProposalMint_V1" {
Scalar value_blind,
# Random blinding factor for the token ID
Scalar token_blind,
# Random blinding factor for the serial number
Scalar serial_blind,
}
circuit "ProposalMint_V1" {
@@ -63,10 +65,19 @@ circuit "ProposalMint_V1" {
tcv = ec_mul_base(token, NULLIFIER_K);
tcr = ec_mul(token_blind, VALUE_COMMIT_RANDOM);
token_commit = ec_add(tcv, tcr);
# Since token_commit is also a curve point, we'll do the same
# Since token commit is also a curve point, we'll do the same
# coordinate dance:
constrain_instance(ec_get_x(token_commit));
constrain_instance(ec_get_y(token_commit));
# Pedersen commitment for coin's serial number
scv = ec_mul_base(serial, NULLIFIER_K);
scr = ec_mul(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));
# At this point we've enforced all of our public inputs.
}

View File

@@ -26,7 +26,7 @@ use darkfi::{
};
use darkfi_money_contract::{
client::{MoneyNote, OwnCoin},
model::{ConsensusStakeParamsV1, ConsensusUnstakeParamsV1, Input, Output, StakeInput},
model::{ConsensusUnstakeParamsV1, Input, Output, StakeInput},
};
use darkfi_sdk::{
crypto::{
@@ -42,24 +42,21 @@ use rand::rngs::OsRng;
use crate::{
client::{
stake_v1::{
ConsensusMintRevealed, TransactionBuilderOutputInfo as StakeTBOI,
TransactionBuilderOutputInfo,
},
stake_v1::{TransactionBuilderOutputInfo as StakeTBOI, TransactionBuilderOutputInfo},
unstake_v1::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
},
model::{
ConsensusRewardParamsV1, HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX, REWARD, REWARD_PALLAS,
SEED_PREFIX, SERIAL_PREFIX, ZERO,
ConsensusProposalMintParamsV1, ConsensusProposalRewardParamsV1, HEADSTART, MU_RHO_PREFIX,
MU_Y_PREFIX, REWARD, REWARD_PALLAS, SEED_PREFIX, SERIAL_PREFIX, ZERO,
},
};
pub struct ConsensusProposalCallDebris {
pub unstake_params: ConsensusUnstakeParamsV1,
pub unstake_proofs: Vec<Proof>,
pub reward_params: ConsensusRewardParamsV1,
pub reward_params: ConsensusProposalRewardParamsV1,
pub reward_proofs: Vec<Proof>,
pub stake_params: ConsensusStakeParamsV1,
pub stake_params: ConsensusProposalMintParamsV1,
pub stake_proofs: Vec<Proof>,
pub signature_secret: SecretKey,
}
@@ -100,6 +97,33 @@ impl ConsensusProposalRewardRevealed {
}
}
pub struct ConsensusProposalMintRevealed {
pub coin: Coin,
pub value_commit: pallas::Point,
pub token_commit: pallas::Point,
pub serial_commit: pallas::Point,
}
impl ConsensusProposalMintRevealed {
pub fn to_vec(&self) -> Vec<pallas::Base> {
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
let sercom_coords = self.serial_commit.to_affine().coordinates().unwrap();
// NOTE: It's important to keep these in the same order
// as the `constrain_instance` calls in the zkas code.
vec![
self.coin.inner(),
*valcom_coords.x(),
*valcom_coords.y(),
*tokcom_coords.x(),
*tokcom_coords.y(),
*sercom_coords.x(),
*sercom_coords.y(),
]
}
}
/// Struct holding necessary information to build a proposal transaction.
pub struct ConsensusProposalCallBuilder {
/// `OwnCoin` we're given to use in this builder
@@ -189,6 +213,7 @@ impl ConsensusProposalCallBuilder {
let spend_hook = CONSENSUS_CONTRACT_ID.inner();
let user_data = pallas::Base::random(&mut OsRng);
let coin_blind = pallas::Base::random(&mut OsRng);
let serial_blind = pallas::Scalar::random(&mut OsRng);
info!("Creating stake mint proof for output for proposal");
let (proof, public_inputs, serial) = create_proposal_mint_proof(
@@ -197,6 +222,7 @@ impl ConsensusProposalCallBuilder {
&output,
value_blind,
token_blind,
serial_blind,
burnt_secret_key,
burnt_serial,
spend_hook,
@@ -235,7 +261,12 @@ impl ConsensusProposalCallBuilder {
};
// We now fill this with necessary stuff
let stake_params = ConsensusStakeParamsV1 { input: input.clone(), output: output.clone() };
let serial_commit = public_inputs.serial_commit;
let stake_params = ConsensusProposalMintParamsV1 {
input: input.clone(),
output: output.clone(),
serial_commit,
};
let stake_proofs = vec![proof];
let stake_input = input;
@@ -257,7 +288,7 @@ impl ConsensusProposalCallBuilder {
let y = public_inputs.y;
let rho = public_inputs.rho;
let reward_params =
ConsensusRewardParamsV1 { unstake_input, stake_input, output, slot, y, rho };
ConsensusProposalRewardParamsV1 { unstake_input, stake_input, output, slot, y, rho };
let reward_proofs = vec![proof];
// Now we should have all the params, zk proofs and signature secret.
@@ -334,15 +365,17 @@ pub fn create_proposal_mint_proof(
output: &TransactionBuilderOutputInfo,
value_blind: pallas::Scalar,
token_blind: pallas::Scalar,
serial_blind: pallas::Scalar,
burnt_secret_key: pallas::Base,
burnt_serial: pallas::Base,
spend_hook: pallas::Base,
user_data: pallas::Base,
coin_blind: pallas::Base,
) -> Result<(Proof, ConsensusMintRevealed, pallas::Base)> {
) -> Result<(Proof, ConsensusProposalMintRevealed, pallas::Base)> {
let serial = poseidon_hash([SERIAL_PREFIX, burnt_secret_key, burnt_serial, ZERO]);
let value_commit = pedersen_commitment_u64(output.value, value_blind);
let token_commit = pedersen_commitment_base(output.token_id.inner(), token_blind);
let serial_commit = pedersen_commitment_base(serial, serial_blind);
let (pub_x, pub_y) = output.public_key.xy();
let coin = Coin::from(poseidon_hash([
@@ -356,7 +389,8 @@ pub fn create_proposal_mint_proof(
coin_blind,
]));
let public_inputs = ConsensusMintRevealed { coin, value_commit, token_commit };
let public_inputs =
ConsensusProposalMintRevealed { coin, value_commit, token_commit, serial_commit };
let prover_witnesses = vec![
Witness::Base(Value::known(pub_x)),
@@ -370,6 +404,7 @@ pub fn create_proposal_mint_proof(
Witness::Base(Value::known(user_data)),
Witness::Scalar(Value::known(value_blind)),
Witness::Scalar(Value::known(token_blind)),
Witness::Scalar(Value::known(serial_blind)),
];
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());

View File

@@ -32,7 +32,7 @@ use darkfi_sdk::{
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{model::ConsensusRewardUpdateV1, ConsensusFunction};
use crate::{model::ConsensusProposalRewardUpdateV1, ConsensusFunction};
/// `Consensus::Stake` functions
mod stake_v1;
@@ -235,7 +235,7 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
Ok(consensus_proposal_burn_process_update_v1(cid, update)?)
}
ConsensusFunction::ProposalRewardV1 => {
let update: ConsensusRewardUpdateV1 = deserialize(&update_data[1..])?;
let update: ConsensusProposalRewardUpdateV1 = deserialize(&update_data[1..])?;
Ok(consensus_proposal_reward_process_update_v1(cid, update)?)
}
ConsensusFunction::ProposalMintV1 => {

View File

@@ -36,7 +36,7 @@ use darkfi_sdk::{
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{ConsensusRewardParamsV1, ZERO},
model::{ConsensusProposalRewardParamsV1, ZERO},
ConsensusFunction,
};
@@ -160,7 +160,7 @@ pub(crate) fn consensus_proposal_burn_process_instruction_v1(
}
// Verify next call StakeInput is the same as this calls input
let next_params: ConsensusRewardParamsV1 = deserialize(&next.data[1..])?;
let next_params: ConsensusProposalRewardParamsV1 = deserialize(&next.data[1..])?;
if input != &next_params.unstake_input {
msg!("[ConsensusProposalBurnV1] Error: Next call input mismatch");
return Err(MoneyError::NextCallInputMissmatch.into())

View File

@@ -17,11 +17,10 @@
*/
use darkfi_money_contract::{
error::MoneyError,
model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1},
CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1,
error::MoneyError, model::ConsensusStakeUpdateV1, CONSENSUS_CONTRACT_COINS_TREE,
CONSENSUS_CONTRACT_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_COIN_ROOTS_TREE,
CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{
@@ -37,7 +36,7 @@ use darkfi_sdk::{
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{ConsensusRewardParamsV1, ZERO},
model::{ConsensusProposalMintParamsV1, ConsensusProposalRewardParamsV1, ZERO},
ConsensusFunction,
};
@@ -48,7 +47,7 @@ pub(crate) fn consensus_proposal_mint_get_metadata_v1(
calls: Vec<ContractCall>,
) -> Result<Vec<u8>, ContractError> {
let self_ = &calls[call_idx as usize];
let params: ConsensusStakeParamsV1 = deserialize(&self_.data[1..])?;
let params: ConsensusProposalMintParamsV1 = deserialize(&self_.data[1..])?;
// Public inputs for the ZK proofs we have to verify
let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
@@ -59,6 +58,7 @@ pub(crate) fn consensus_proposal_mint_get_metadata_v1(
let output = &params.output;
let value_coords = output.value_commit.to_affine().coordinates().unwrap();
let token_coords = output.token_commit.to_affine().coordinates().unwrap();
let serial_coords = &params.serial_commit.to_affine().coordinates().unwrap();
zk_public_inputs.push((
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1.to_string(),
@@ -68,6 +68,8 @@ pub(crate) fn consensus_proposal_mint_get_metadata_v1(
*value_coords.y(),
*token_coords.x(),
*token_coords.y(),
*serial_coords.x(),
*serial_coords.y(),
],
));
@@ -88,7 +90,7 @@ pub(crate) fn consensus_proposal_mint_process_instruction_v1(
calls: Vec<ContractCall>,
) -> Result<Vec<u8>, ContractError> {
let self_ = &calls[call_idx as usize];
let params: ConsensusStakeParamsV1 = deserialize(&self_.data[1..])?;
let params: ConsensusProposalMintParamsV1 = deserialize(&self_.data[1..])?;
// Access the necessary databases where there is information to
// validate this state transition.
@@ -149,7 +151,7 @@ pub(crate) fn consensus_proposal_mint_process_instruction_v1(
}
// Verify previous call input is the same as this calls StakeInput
let previous_params: ConsensusRewardParamsV1 = deserialize(&previous.data[1..])?;
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");

View File

@@ -17,8 +17,7 @@
*/
use darkfi_money_contract::{
error::MoneyError,
model::{ConsensusStakeParamsV1, ConsensusUnstakeParamsV1},
error::MoneyError, model::ConsensusUnstakeParamsV1,
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1,
};
use darkfi_sdk::{
@@ -37,8 +36,9 @@ use darkfi_serial::{deserialize, Encodable, WriteExt};
use crate::{
error::ConsensusError,
model::{
ConsensusRewardParamsV1, ConsensusRewardUpdateV1, SlotCheckpoint, HEADSTART, MU_RHO_PREFIX,
MU_Y_PREFIX, REWARD, ZERO,
ConsensusProposalMintParamsV1, ConsensusProposalRewardParamsV1,
ConsensusProposalRewardUpdateV1, SlotCheckpoint, HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX,
REWARD, ZERO,
},
ConsensusFunction,
};
@@ -50,7 +50,7 @@ pub(crate) fn consensus_proposal_reward_get_metadata_v1(
calls: Vec<ContractCall>,
) -> Result<Vec<u8>, ContractError> {
let self_ = &calls[call_idx as usize];
let params: ConsensusRewardParamsV1 = deserialize(&self_.data[1..])?;
let params: ConsensusProposalRewardParamsV1 = deserialize(&self_.data[1..])?;
// Public inputs for the ZK proofs we have to verify
let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
@@ -121,7 +121,7 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
calls: Vec<ContractCall>,
) -> Result<Vec<u8>, ContractError> {
let self_ = &calls[call_idx as usize];
let params: ConsensusRewardParamsV1 = deserialize(&self_.data[1..])?;
let params: ConsensusProposalRewardParamsV1 = deserialize(&self_.data[1..])?;
// ===================================
// Perform the actual state transition
@@ -205,7 +205,7 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
}
// Verify next call StakeInput is the same as this calls input
let next_params: ConsensusStakeParamsV1 = deserialize(&next.data[1..])?;
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())
@@ -216,7 +216,7 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
}
// Create a state update.
let update = ConsensusRewardUpdateV1 {};
let update = ConsensusProposalRewardUpdateV1 {};
let mut update_data = vec![];
update_data.write_u8(ConsensusFunction::ProposalRewardV1 as u8)?;
update.encode(&mut update_data)?;
@@ -227,7 +227,7 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
/// `process_update` function for `Consensus::ProposalRewardV1`
pub(crate) fn consensus_proposal_reward_process_update_v1(
_cid: ContractId,
_update: ConsensusRewardUpdateV1,
_update: ConsensusProposalRewardUpdateV1,
) -> ContractResult {
// This contract call doesn't produce any updates
Ok(())

View File

@@ -20,9 +20,9 @@ use darkfi_money_contract::model::{Input, Output, StakeInput};
use darkfi_sdk::pasta::pallas;
use darkfi_serial::{SerialDecodable, SerialEncodable};
/// Parameters for `Consensus::Reward`
/// Parameters for `Consensus::ProposalReward`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusRewardParamsV1 {
pub struct ConsensusProposalRewardParamsV1 {
/// Anonymous input of `Consensus::Unstake`
pub unstake_input: Input,
/// Burnt token revealed info of `Consensus::Stake`
@@ -37,9 +37,20 @@ pub struct ConsensusRewardParamsV1 {
pub rho: pallas::Base,
}
/// Parameters for `Consensus::ProposalMint`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusProposalMintParamsV1 {
/// Burnt token revealed info
pub input: StakeInput,
/// Anonymous output
pub output: Output,
/// Pedersen commitment for the output's serial number
pub serial_commit: pallas::Point,
}
/// State update for `Consensus::Reward`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusRewardUpdateV1 {}
pub struct ConsensusProposalRewardUpdateV1 {}
// Consensus parameters configuration.
// Note: Always verify `pallas::Base` are correct, in case of changes,