mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/consensus: create serial commitment in ProposalMint and constrain it
This commit is contained in:
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 = ¶ms.output;
|
||||
let value_coords = output.value_commit.to_affine().coordinates().unwrap();
|
||||
let token_coords = output.token_commit.to_affine().coordinates().unwrap();
|
||||
let serial_coords = ¶ms.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");
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user