contract/consensus: use new ConsensusMint proof in ConsensusStake, minor cleanup

This commit is contained in:
aggstam
2023-05-28 04:23:12 +03:00
parent 1615ea1e75
commit b470804fbf
21 changed files with 319 additions and 430 deletions

View File

@@ -23,19 +23,17 @@ use darkfi::{
zkas::ZkBinary,
Result,
};
use darkfi_money_contract::client::MoneyNote;
use darkfi_money_contract::client::{ConsensusNote, MoneyNote};
use darkfi_sdk::{
crypto::{
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash, Coin,
MerkleNode, MerklePosition, Nullifier, PublicKey, SecretKey, TokenId,
MerkleNode, MerklePosition, Nullifier, PublicKey, SecretKey,
},
incrementalmerkletree::Hashable,
pasta::pallas,
};
use rand::rngs::OsRng;
use crate::client::ConsensusNote;
pub struct TransactionBuilderInputInfo {
pub leaf_position: MerklePosition,
pub merkle_path: Vec<MerkleNode>,
@@ -43,17 +41,21 @@ pub struct TransactionBuilderInputInfo {
pub note: MoneyNote,
}
pub struct TransactionBuilderConsensusInputInfo {
pub struct ConsensusMintOutputInfo {
pub value: u64,
pub epoch: u64,
pub public_key: PublicKey,
pub value_blind: pallas::Scalar,
pub serial: pallas::Base,
pub coin_blind: pallas::Base,
}
pub struct ConsensusBurnInputInfo {
pub leaf_position: MerklePosition,
pub merkle_path: Vec<MerkleNode>,
pub secret: SecretKey,
pub note: ConsensusNote,
}
pub struct TransactionBuilderOutputInfo {
pub value: u64,
pub token_id: TokenId,
pub public_key: PublicKey,
pub value_blind: pallas::Scalar,
}
pub struct ConsensusMintRevealed {
@@ -76,30 +78,32 @@ impl ConsensusMintRevealed {
pub fn create_consensus_mint_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
epoch: u64,
output: &TransactionBuilderOutputInfo,
value_blind: pallas::Scalar,
serial: pallas::Base,
coin_blind: pallas::Base,
output: &ConsensusMintOutputInfo,
) -> Result<(Proof, ConsensusMintRevealed)> {
let epoch_pallas = pallas::Base::from(epoch);
let epoch_pallas = pallas::Base::from(output.epoch);
let value_pallas = pallas::Base::from(output.value);
let value_commit = pedersen_commitment_u64(output.value, value_blind);
let value_commit = pedersen_commitment_u64(output.value, output.value_blind);
let (pub_x, pub_y) = output.public_key.xy();
let coin =
Coin::from(poseidon_hash([pub_x, pub_y, value_pallas, epoch_pallas, serial, coin_blind]));
let coin = Coin::from(poseidon_hash([
pub_x,
pub_y,
value_pallas,
epoch_pallas,
output.serial,
output.coin_blind,
]));
let public_inputs = ConsensusMintRevealed { epoch, coin, value_commit };
let public_inputs = ConsensusMintRevealed { epoch: output.epoch, coin, value_commit };
let prover_witnesses = vec![
Witness::Base(Value::known(pub_x)),
Witness::Base(Value::known(pub_y)),
Witness::Base(Value::known(value_pallas)),
Witness::Base(Value::known(epoch_pallas)),
Witness::Base(Value::known(serial)),
Witness::Base(Value::known(coin_blind)),
Witness::Scalar(Value::known(value_blind)),
Witness::Base(Value::known(output.serial)),
Witness::Base(Value::known(output.coin_blind)),
Witness::Scalar(Value::known(output.value_blind)),
];
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
@@ -139,14 +143,13 @@ impl ConsensusBurnRevealed {
pub fn create_consensus_burn_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
input: &TransactionBuilderConsensusInputInfo,
value_blind: pallas::Scalar,
input: &ConsensusBurnInputInfo,
) -> Result<(Proof, ConsensusBurnRevealed, SecretKey)> {
let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
let epoch = input.note.epoch;
let epoch_pallas = pallas::Base::from(epoch);
let value_pallas = pallas::Base::from(input.note.value);
let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
let value_commit = pedersen_commitment_u64(input.note.value, input.value_blind);
let public_key = PublicKey::from_secret(input.secret);
let (pub_x, pub_y) = public_key.xy();
@@ -186,7 +189,7 @@ pub fn create_consensus_burn_proof(
Witness::Base(Value::known(epoch_pallas)),
Witness::Base(Value::known(input.note.serial)),
Witness::Base(Value::known(input.note.coin_blind)),
Witness::Scalar(Value::known(value_blind)),
Witness::Scalar(Value::known(input.value_blind)),
Witness::Base(Value::known(input.secret.inner())),
Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),

View File

@@ -23,7 +23,10 @@ use darkfi::{
zkas::ZkBinary,
Result,
};
use darkfi_money_contract::model::ClearInput;
use darkfi_money_contract::{
client::ConsensusNote,
model::{ClearInput, ConsensusOutput},
};
use darkfi_sdk::{
crypto::{note::AeadEncryptedNote, pasta_prelude::*, Keypair, PublicKey, DARK_TOKEN_ID},
pasta::pallas,
@@ -32,11 +35,8 @@ use log::{debug, info};
use rand::rngs::OsRng;
use crate::{
client::{
common::{create_consensus_mint_proof, TransactionBuilderOutputInfo},
ConsensusNote,
},
model::{ConsensusGenesisStakeParamsV1, ConsensusOutput},
client::common::{create_consensus_mint_proof, ConsensusMintOutputInfo},
model::ConsensusGenesisStakeParamsV1,
};
pub struct ConsensusGenesisStakeCallDebris {
@@ -71,29 +71,21 @@ impl ConsensusGenesisStakeCallBuilder {
// We just create the pedersen commitment blinds here. We simply
// enforce that the clear input and the anon output have the same
// commitments. Not sure if this can be avoided, but also is it
// really necessary to avoid?
// commitments.
let value_blind = pallas::Scalar::random(&mut OsRng);
let token_blind = pallas::Scalar::random(&mut OsRng);
let serial = pallas::Base::random(&mut OsRng);
let coin_blind = pallas::Base::random(&mut OsRng);
let c_input =
ClearInput { value, token_id, value_blind, token_blind, signature_public: public_key };
let output = TransactionBuilderOutputInfo { value, token_id, public_key };
let serial = pallas::Base::random(&mut OsRng);
let coin_blind = pallas::Base::random(&mut OsRng);
let output =
ConsensusMintOutputInfo { value, epoch, public_key, value_blind, serial, coin_blind };
info!("Creating genesis stake mint proof for output");
let (proof, public_inputs) = create_consensus_mint_proof(
&self.mint_zkbin,
&self.mint_pk,
epoch,
&output,
value_blind,
serial,
coin_blind,
)?;
let (proof, public_inputs) =
create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
// Encrypted note
let note = ConsensusNote { serial, value: output.value, epoch, coin_blind, value_blind };

View File

@@ -25,15 +25,6 @@
//! the necessary objects provided by the caller. This is intentional, so we
//! are able to abstract away any wallet interfaces to client implementations.
use darkfi_money_contract::client::{MoneyNote, OwnCoin};
use darkfi_sdk::{
crypto::{pasta_prelude::Field, Coin, MerklePosition, Nullifier, SecretKey, DARK_TOKEN_ID},
pasta::pallas,
};
use darkfi_serial::{SerialDecodable, SerialEncodable};
use crate::model::ZERO;
/// Common functions
pub(crate) mod common;
@@ -50,61 +41,3 @@ pub mod proposal_v1;
/// `Consensus::UnstakeV1` API
pub mod unstake_v1;
/// `ConsensusNote` holds the inner attributes of a `Coin`.
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusNote {
/// Serial number of the coin, used for the nullifier
pub serial: pallas::Base,
/// Value of the coin
pub value: u64,
/// Epoch the coin was minted
pub epoch: u64,
/// Blinding factor for the coin bulla
pub coin_blind: pallas::Base,
/// Blinding factor for the value pedersen commitment
pub value_blind: pallas::Scalar,
}
impl From<ConsensusNote> for MoneyNote {
fn from(consensus_note: ConsensusNote) -> Self {
MoneyNote {
serial: consensus_note.serial,
value: consensus_note.value,
token_id: *DARK_TOKEN_ID,
spend_hook: ZERO,
user_data: ZERO,
coin_blind: consensus_note.coin_blind,
value_blind: consensus_note.value_blind,
token_blind: pallas::Scalar::zero(),
memo: vec![],
}
}
}
/// `ConsensusOwnCoin` is a representation of `Coin` with its respective metadata.
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusOwnCoin {
/// The coin hash
pub coin: Coin,
/// The attached `ConsensusNote`
pub note: ConsensusNote,
/// Coin's secret key
pub secret: SecretKey,
/// Coin's nullifier
pub nullifier: Nullifier,
/// Coin's leaf position in the Merkle tree of coins
pub leaf_position: MerklePosition,
}
impl From<ConsensusOwnCoin> for OwnCoin {
fn from(consensus_own_coin: ConsensusOwnCoin) -> Self {
OwnCoin {
coin: consensus_own_coin.coin,
note: consensus_own_coin.note.into(),
secret: consensus_own_coin.secret,
nullifier: consensus_own_coin.nullifier,
leaf_position: consensus_own_coin.leaf_position,
}
}
}

View File

@@ -26,13 +26,13 @@ use darkfi::{
};
use darkfi_money_contract::{
client::{MoneyNote, OwnCoin},
model::{Input, Output, StakeInput},
model::{ConsensusInput, Input, Output, PALLAS_ZERO},
};
use darkfi_sdk::{
crypto::{
ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_base,
pedersen_commitment_u64, poseidon_hash, Coin, MerkleTree, Nullifier, PublicKey, SecretKey,
CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
TokenId, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
},
incrementalmerkletree::Tree,
pasta::{group::ff::FromUniformBytes, pallas},
@@ -41,17 +41,21 @@ use log::{debug, info};
use rand::rngs::OsRng;
use crate::{
client::{
common::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
stake_v1::{TransactionBuilderOutputInfo as StakeTBOI, TransactionBuilderOutputInfo},
},
client::common::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
model::{
ConsensusProposalBurnParamsV1, ConsensusProposalMintParamsV1,
ConsensusProposalRewardParamsV1, HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX, REWARD,
REWARD_PALLAS, SEED_PREFIX, SERIAL_PREFIX, ZERO,
REWARD_PALLAS, SEED_PREFIX, SERIAL_PREFIX,
},
};
// TODO: Remove TransactionBuilderOutputInfo
pub struct TransactionBuilderOutputInfo {
pub value: u64,
pub token_id: TokenId,
pub public_key: PublicKey,
}
pub struct ConsensusProposalCallDebris {
pub burn_params: ConsensusProposalBurnParamsV1,
pub burn_proofs: Vec<Proof>,
@@ -218,7 +222,8 @@ impl ConsensusProposalCallBuilder {
let signature_public = public_inputs.signature_public;
debug!("Building anonymous output for proposal");
let output = StakeTBOI { value: new_value, token_id, public_key: self.recipient };
let output =
TransactionBuilderOutputInfo { value: new_value, token_id, public_key: self.recipient };
debug!("Finished building output for proposal");
let burnt_serial = self.coin.note.serial;
@@ -264,8 +269,9 @@ impl ConsensusProposalCallBuilder {
note: encrypted_note,
};
let input = StakeInput {
token_blind,
// TODO: epoch = current
let input = ConsensusInput {
epoch: 0,
value_commit: public_inputs.value_commit,
nullifier,
merkle_root,
@@ -346,11 +352,11 @@ pub fn create_proposal_reward_proof(
let nullifier = Nullifier::from(poseidon_hash([secret_key, serial]));
let public_key = PublicKey::from_secret(secret_key.into());
let value_commit = pedersen_commitment_u64(value, value_blind);
let new_serial = poseidon_hash([SERIAL_PREFIX, secret_key, serial, ZERO]);
let new_serial = poseidon_hash([SERIAL_PREFIX, secret_key, serial, PALLAS_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]);
let seed = poseidon_hash([SEED_PREFIX, serial, PALLAS_ZERO]);
// NOTE: slot checkpoint eta to be renamed to previous_eta,
// corresponding to previous block eta.
let mut vrf_input = [0u8; 64];
@@ -416,7 +422,7 @@ pub fn create_proposal_mint_proof(
user_data: pallas::Base,
coin_blind: pallas::Base,
) -> Result<(Proof, ConsensusProposalMintRevealed, pallas::Base)> {
let serial = poseidon_hash([SERIAL_PREFIX, burnt_secret_key, burnt_serial, ZERO]);
let serial = poseidon_hash([SERIAL_PREFIX, burnt_secret_key, burnt_serial, PALLAS_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);

View File

@@ -19,78 +19,47 @@
//! This API is crufty. Please rework it into something nice to read and nice to use.
use darkfi::{
zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
zk::{Proof, ProvingKey},
zkas::ZkBinary,
Result,
};
use darkfi_money_contract::{
client::{MoneyNote, OwnCoin},
model::{ConsensusStakeParamsV1, Output, StakeInput},
client::{ConsensusNote, OwnCoin},
model::{ConsensusInput, ConsensusOutput, ConsensusStakeParamsV1},
};
use darkfi_sdk::{
crypto::{
note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_base,
pedersen_commitment_u64, poseidon_hash, Coin, MerkleNode, Nullifier, PublicKey, TokenId,
CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
note::AeadEncryptedNote, pasta_prelude::*, MerkleNode, Nullifier, PublicKey, SecretKey,
DARK_TOKEN_ID,
},
pasta::pallas,
};
use log::{debug, info};
use rand::rngs::OsRng;
use crate::client::common::{create_consensus_mint_proof, ConsensusMintOutputInfo};
pub struct ConsensusStakeCallDebris {
pub params: ConsensusStakeParamsV1,
pub proofs: Vec<Proof>,
}
pub struct ConsensusMintRevealed {
pub coin: Coin,
pub value_commit: pallas::Point,
pub token_commit: pallas::Point,
}
impl ConsensusMintRevealed {
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();
// 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(),
]
}
}
pub struct TransactionBuilderOutputInfo {
pub value: u64,
pub token_id: TokenId,
pub public_key: PublicKey,
pub signature_secret: SecretKey,
}
/// Struct holding necessary information to build a `Consensus::StakeV1` contract call.
pub struct ConsensusStakeCallBuilder {
/// `OwnCoin` we're given to use in this builder
pub coin: OwnCoin,
/// Recipient's public key
pub recipient: PublicKey,
/// Epoch staked coin is minted
pub epoch: u64,
/// Blinding factor for value commitment
pub value_blind: pallas::Scalar,
/// Blinding factor for `token_id`
pub token_blind: pallas::Scalar,
/// Revealed nullifier
pub nullifier: Nullifier,
/// Revealed Merkle root
pub merkle_root: MerkleNode,
/// Public key for the signature
pub signature_public: PublicKey,
/// `Mint_V1` zkas circuit ZkBinary
/// `ConsensusMint_V1` zkas circuit ZkBinary
pub mint_zkbin: ZkBinary,
/// Proving key for the `Mint_V1` zk circuit
/// Proving key for the `ConsensusMint_V1` zk circuit
pub mint_pk: ProvingKey,
}
@@ -101,59 +70,47 @@ impl ConsensusStakeCallBuilder {
assert!(self.coin.note.token_id == *DARK_TOKEN_ID);
debug!("Building anonymous output");
let output = TransactionBuilderOutputInfo {
let serial = pallas::Base::random(&mut OsRng);
let coin_blind = pallas::Base::random(&mut OsRng);
let public_key = PublicKey::from_secret(self.coin.secret);
let output = ConsensusMintOutputInfo {
value: self.coin.note.value,
token_id: self.coin.note.token_id,
public_key: self.recipient,
epoch: self.epoch,
public_key,
value_blind: self.value_blind,
serial,
coin_blind,
};
debug!("Finished building output");
let serial = pallas::Base::random(&mut OsRng);
let spend_hook = CONSENSUS_CONTRACT_ID.inner();
let user_data = pallas::Base::random(&mut OsRng);
let coin_blind = pallas::Base::random(&mut OsRng);
info!("Creating stake mint proof for output");
let (proof, public_inputs) = create_stake_mint_proof(
&self.mint_zkbin,
&self.mint_pk,
&output,
self.value_blind,
self.token_blind,
serial,
spend_hook,
user_data,
coin_blind,
)?;
let (proof, public_inputs) =
create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
// Encrypted note
let note = MoneyNote {
let note = ConsensusNote {
serial,
value: output.value,
token_id: output.token_id,
spend_hook,
user_data,
epoch: self.epoch,
coin_blind,
value_blind: self.value_blind,
token_blind: self.token_blind,
memo: vec![],
};
let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
let output = Output {
let output = ConsensusOutput {
value_commit: public_inputs.value_commit,
token_commit: public_inputs.token_commit,
coin: public_inputs.coin,
note: encrypted_note,
};
let input = StakeInput {
token_blind: self.token_blind,
let input = ConsensusInput {
epoch: self.epoch,
value_commit: public_inputs.value_commit,
nullifier: self.nullifier,
merkle_root: self.merkle_root,
signature_public: self.signature_public,
signature_public: public_key,
};
// We now fill this with necessary stuff
@@ -162,55 +119,8 @@ impl ConsensusStakeCallBuilder {
// Now we should have all the params and zk proof.
// We return it all and let the caller deal with it.
let debris = ConsensusStakeCallDebris { params, proofs };
let debris =
ConsensusStakeCallDebris { params, proofs, signature_secret: self.coin.secret };
Ok(debris)
}
}
#[allow(clippy::too_many_arguments)]
pub fn create_stake_mint_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
output: &TransactionBuilderOutputInfo,
value_blind: pallas::Scalar,
token_blind: pallas::Scalar,
serial: pallas::Base,
spend_hook: pallas::Base,
user_data: pallas::Base,
coin_blind: pallas::Base,
) -> Result<(Proof, ConsensusMintRevealed)> {
let value_commit = pedersen_commitment_u64(output.value, value_blind);
let token_commit = pedersen_commitment_base(output.token_id.inner(), token_blind);
let (pub_x, pub_y) = output.public_key.xy();
let coin = Coin::from(poseidon_hash([
pub_x,
pub_y,
pallas::Base::from(output.value),
output.token_id.inner(),
serial,
spend_hook,
user_data,
coin_blind,
]));
let public_inputs = ConsensusMintRevealed { coin, value_commit, token_commit };
let prover_witnesses = vec![
Witness::Base(Value::known(pub_x)),
Witness::Base(Value::known(pub_y)),
Witness::Base(Value::known(pallas::Base::from(output.value))),
Witness::Base(Value::known(output.token_id.inner())),
Witness::Base(Value::known(serial)),
Witness::Base(Value::known(coin_blind)),
Witness::Base(Value::known(spend_hook)),
Witness::Base(Value::known(user_data)),
Witness::Scalar(Value::known(value_blind)),
Witness::Scalar(Value::known(token_blind)),
];
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
Ok((proof, public_inputs))
}

View File

@@ -23,7 +23,10 @@ use darkfi::{
zkas::ZkBinary,
Result,
};
use darkfi_money_contract::model::{ConsensusUnstakeParamsV1, UnstakeInput};
use darkfi_money_contract::{
client::ConsensusOwnCoin,
model::{ConsensusInput, ConsensusUnstakeParamsV1},
};
use darkfi_sdk::{
crypto::{pasta_prelude::*, MerkleTree, SecretKey},
incrementalmerkletree::Tree,
@@ -32,10 +35,7 @@ use darkfi_sdk::{
use log::{debug, info};
use rand::rngs::OsRng;
use crate::client::{
common::{create_consensus_burn_proof, TransactionBuilderConsensusInputInfo},
ConsensusOwnCoin,
};
use crate::client::common::{create_consensus_burn_proof, ConsensusBurnInputInfo};
pub struct ConsensusUnstakeCallDebris {
pub params: ConsensusUnstakeParamsV1,
@@ -65,20 +65,22 @@ impl ConsensusUnstakeCallBuilder {
let leaf_position = self.coin.leaf_position;
let root = self.tree.root(0).unwrap();
let merkle_path = self.tree.authentication_path(leaf_position, &root).unwrap();
let input = TransactionBuilderConsensusInputInfo {
let value_blind = pallas::Scalar::random(&mut OsRng);
let input = ConsensusBurnInputInfo {
leaf_position,
merkle_path,
secret: self.coin.secret,
note: self.coin.note.clone(),
value_blind,
};
debug!("Finished building input");
let value_blind = pallas::Scalar::random(&mut OsRng);
info!("Creating unstake burn proof for input");
let value_blind = input.value_blind;
let (proof, public_inputs, signature_secret) =
create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input, value_blind)?;
create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input)?;
let input = UnstakeInput {
let input = ConsensusInput {
epoch: self.coin.note.epoch,
value_commit: public_inputs.value_commit,
nullifier: public_inputs.nullifier,

View File

@@ -17,8 +17,9 @@
*/
use darkfi_money_contract::{
error::MoneyError, model::ConsensusStakeUpdateV1, CONSENSUS_CONTRACT_COINS_TREE,
CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
error::MoneyError,
model::{ConsensusStakeUpdateV1, PALLAS_ZERO},
CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{pasta_prelude::*, pedersen_commitment_u64, ContractId, DARK_TOKEN_ID},
@@ -31,10 +32,7 @@ use darkfi_sdk::{
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{ConsensusGenesisStakeParamsV1, ZERO},
ConsensusFunction,
};
use crate::{model::ConsensusGenesisStakeParamsV1, ConsensusFunction};
/// `get_metadata` function for `Consensus::GenesisStakeV1`
pub(crate) fn consensus_genesis_stake_get_metadata_v1(
@@ -51,7 +49,7 @@ pub(crate) fn consensus_genesis_stake_get_metadata_v1(
let signature_pubkeys = vec![params.input.signature_public];
// Genesis stake only happens on epoch 0
let epoch = ZERO;
let epoch = PALLAS_ZERO;
// Grab the pedersen commitment from the anonymous output
let output = &params.output;

View File

@@ -17,8 +17,10 @@
*/
use darkfi_money_contract::{
error::MoneyError, model::ConsensusUnstakeUpdateV1, CONSENSUS_CONTRACT_COIN_ROOTS_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
error::MoneyError,
model::{ConsensusUnstakeUpdateV1, PALLAS_ZERO},
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
MONEY_CONTRACT_ZKAS_BURN_NS_V1,
};
use darkfi_sdk::{
crypto::{
@@ -34,7 +36,7 @@ use darkfi_sdk::{
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{ConsensusProposalBurnParamsV1, ConsensusProposalRewardParamsV1, ZERO},
model::{ConsensusProposalBurnParamsV1, ConsensusProposalRewardParamsV1},
ConsensusFunction,
};
@@ -139,7 +141,7 @@ pub(crate) fn consensus_proposal_burn_process_instruction_v1(
}
// Check if spend hook is set and its correctness
if input.spend_hook == ZERO {
if input.spend_hook == PALLAS_ZERO {
msg!("[ConsensusProposalBurnV1] Error: Missing spend hook");
return Err(MoneyError::StakeMissingSpendHook.into())
}

View File

@@ -17,16 +17,14 @@
*/
use darkfi_money_contract::{
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,
error::MoneyError,
model::{ConsensusStakeUpdateV1, PALLAS_ZERO},
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::{
pasta_prelude::*, pedersen_commitment_base, ContractId, MerkleNode, CONSENSUS_CONTRACT_ID,
DARK_TOKEN_ID,
},
crypto::{pasta_prelude::*, ContractId, MerkleNode, CONSENSUS_CONTRACT_ID},
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle_add, msg,
@@ -36,7 +34,7 @@ use darkfi_sdk::{
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{ConsensusProposalMintParamsV1, ConsensusProposalRewardParamsV1, ZERO},
model::{ConsensusProposalMintParamsV1, ConsensusProposalRewardParamsV1},
ConsensusFunction,
};
@@ -104,11 +102,13 @@ pub(crate) fn consensus_proposal_mint_process_instruction_v1(
let input = &params.input;
let output = &params.output;
/*
// Only native token can be minted in a proposal
if output.token_commit != pedersen_commitment_base(DARK_TOKEN_ID.inner(), input.token_blind) {
msg!("[ConsensusProposalMintV1] Error: Input used non-native token");
return Err(MoneyError::StakeInputNonNativeToken.into())
}
*/
// Verify value commits match
if output.value_commit != input.value_commit {
@@ -161,7 +161,7 @@ pub(crate) fn consensus_proposal_mint_process_instruction_v1(
// If spend hook is set, check its correctness
let previous_input = &previous_params.burnt_input;
if previous_input.spend_hook != ZERO &&
if previous_input.spend_hook != PALLAS_ZERO &&
previous_input.spend_hook != CONSENSUS_CONTRACT_ID.inner()
{
msg!("[ConsensusProposalMintV1] Error: Invoking contract call does not match spend hook in input");

View File

@@ -16,11 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi_money_contract::{error::MoneyError, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1};
use darkfi_money_contract::{
error::MoneyError, model::PALLAS_ZERO, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1,
};
use darkfi_sdk::{
crypto::{
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash,
ContractId, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, CONSENSUS_CONTRACT_ID,
},
error::{ContractError, ContractResult},
msg,
@@ -35,7 +36,7 @@ use crate::{
model::{
ConsensusProposalBurnParamsV1, ConsensusProposalMintParamsV1,
ConsensusProposalRewardParamsV1, ConsensusProposalRewardUpdateV1, SlotCheckpoint,
HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX, REWARD, ZERO,
HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX, REWARD,
},
ConsensusFunction,
};
@@ -152,12 +153,14 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
let mint_input = &params.mint_input;
let output = &params.output;
/*
// Only native token can be rewarded in a proposal
let dark_token_commit = pedersen_commitment_base(DARK_TOKEN_ID.inner(), mint_input.token_blind);
if burnt_input.token_commit != dark_token_commit || output.token_commit != dark_token_commit {
msg!("[ConsensusProposalRewardV1] Error: Input used non-native token");
return Err(MoneyError::StakeInputNonNativeToken.into())
}
*/
// Verify value commits match
let mut valcom_total = pallas::Point::identity();
@@ -197,7 +200,7 @@ pub(crate) fn consensus_proposal_reward_process_instruction_v1(
}
// If spend hook is set, check its correctness
if previous_input.spend_hook != ZERO &&
if previous_input.spend_hook != PALLAS_ZERO &&
previous_input.spend_hook != CONSENSUS_CONTRACT_ID.inner()
{
msg!("[ConsensusProposalRewardV1] Error: Invoking contract call does not match spend hook in input");

View File

@@ -18,16 +18,14 @@
use darkfi_money_contract::{
error::MoneyError,
model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1},
model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1, PALLAS_ZERO},
CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, MONEY_CONTRACT_COIN_ROOTS_TREE,
MONEY_CONTRACT_NULLIFIERS_TREE,
};
use darkfi_sdk::{
crypto::{
pasta_prelude::*, pedersen_commitment_base, ContractId, MerkleNode, CONSENSUS_CONTRACT_ID,
DARK_TOKEN_ID, MONEY_CONTRACT_ID,
},
crypto::{pasta_prelude::*, ContractId, MerkleNode, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
merkle_add, msg,
@@ -36,7 +34,7 @@ use darkfi_sdk::{
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{model::ZERO, ConsensusFunction};
use crate::ConsensusFunction;
/// `get_metadata` function for `Consensus::StakeV1`
pub(crate) fn consensus_stake_get_metadata_v1(
@@ -52,20 +50,17 @@ pub(crate) fn consensus_stake_get_metadata_v1(
// Public keys for the transaction signatures we have to verify
let signature_pubkeys = vec![params.input.signature_public];
// TODO: Grab the minting epoch from the verifying slot
//let verifying_slot = get_verifying_slot_epoch();
let epoch = PALLAS_ZERO;
// Grab the pedersen commitment from the anonymous output
let output = &params.output;
let value_coords = output.value_commit.to_affine().coordinates().unwrap();
let token_coords = output.token_commit.to_affine().coordinates().unwrap();
zk_public_inputs.push((
MONEY_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
vec![
output.coin.inner(),
*value_coords.x(),
*value_coords.y(),
*token_coords.x(),
*token_coords.y(),
],
CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
vec![epoch, output.coin.inner(), *value_coords.x(), *value_coords.y()],
));
// Serialize everything gathered and return it
@@ -99,12 +94,6 @@ pub(crate) fn consensus_stake_process_instruction_v1(
let input = &params.input;
let output = &params.output;
// Only native token can be staked
if output.token_commit != pedersen_commitment_base(DARK_TOKEN_ID.inner(), input.token_blind) {
msg!("[ConsensusStakeV1] Error: Input used non-native token");
return Err(MoneyError::StakeInputNonNativeToken.into())
}
// Verify value commits match
if output.value_commit != input.value_commit {
msg!("[ConsensusStakeV1] Error: Value commitments do not match");
@@ -152,7 +141,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
}
// If spend hook is set, check its correctness
if previous_input.spend_hook != ZERO &&
if previous_input.spend_hook != PALLAS_ZERO &&
previous_input.spend_hook != CONSENSUS_CONTRACT_ID.inner()
{
msg!("[ConsensusStakeV1] Error: Invoking contract call does not match spend hook in input");

View File

@@ -16,24 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi_money_contract::model::{ClearInput, Input, Output, StakeInput};
use darkfi_money_contract::model::{ClearInput, ConsensusInput, ConsensusOutput, Input, Output};
use darkfi_sdk::{
crypto::{ecvrf::VrfProof, note::AeadEncryptedNote, Coin, PublicKey},
crypto::{ecvrf::VrfProof, PublicKey},
pasta::pallas,
};
use darkfi_serial::{SerialDecodable, SerialEncodable};
/// A consensus contract call's anonymous output
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusOutput {
/// Pedersen commitment for the output's value
pub value_commit: pallas::Point,
/// Minted coin
pub coin: Coin,
/// AEAD encrypted note
pub note: AeadEncryptedNote,
}
/// Parameters for `Consensus::GenesisStake`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusGenesisStakeParamsV1 {
@@ -62,7 +51,7 @@ pub struct ConsensusProposalRewardParamsV1 {
/// Burnt coin public key used in VRF
pub burnt_public_key: PublicKey,
/// Burnt token revealed info of `Consensus::ProposalMint`
pub mint_input: StakeInput,
pub mint_input: ConsensusInput,
/// Anonymous output
pub output: Output,
/// Pedersen commitment for the output's serial number
@@ -81,7 +70,7 @@ pub struct ConsensusProposalRewardParamsV1 {
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusProposalMintParamsV1 {
/// Burnt token revealed info
pub input: StakeInput,
pub input: ConsensusInput,
/// Anonymous output
pub output: Output,
/// Pedersen commitment for the output's serial number
@@ -99,8 +88,6 @@ pub struct ConsensusProposalRewardUpdateV1 {}
pub const REWARD: u64 = 1;
// Reward `pallas::Base`, calculated by: pallas::Base::from(REWARD)
pub const REWARD_PALLAS: pallas::Base = pallas::Base::from_raw([1, 0, 0, 0]);
// `pallas::Base` used as prefix/suffix in poseidon hash
pub const ZERO: pallas::Base = pallas::Base::zero();
// Serial prefix, calculated by: pallas::Base::from(2)
pub const SERIAL_PREFIX: pallas::Base = pallas::Base::from_raw([2, 0, 0, 0]);
// Seed prefix, calculated by: pallas::Base::from(3)

View File

@@ -48,17 +48,20 @@ use darkfi_consensus_contract::{
client::{
genesis_stake_v1::ConsensusGenesisStakeCallBuilder,
proposal_v1::ConsensusProposalCallBuilder, stake_v1::ConsensusStakeCallBuilder,
unstake_v1::ConsensusUnstakeCallBuilder, ConsensusNote, ConsensusOwnCoin,
unstake_v1::ConsensusUnstakeCallBuilder,
},
model::{ConsensusGenesisStakeParamsV1, ConsensusOutput, ConsensusProposalMintParamsV1},
model::{ConsensusGenesisStakeParamsV1, ConsensusProposalMintParamsV1},
ConsensusFunction,
};
use darkfi_money_contract::{
client::{
stake_v1::MoneyStakeCallBuilder, transfer_v1::TransferCallBuilder,
unstake_v1::MoneyUnstakeCallBuilder, MoneyNote, OwnCoin,
unstake_v1::MoneyUnstakeCallBuilder, ConsensusNote, ConsensusOwnCoin, MoneyNote, OwnCoin,
},
model::{
ConsensusOutput, ConsensusStakeParamsV1, MoneyTransferParamsV1, MoneyUnstakeParamsV1,
Output,
},
model::{ConsensusStakeParamsV1, MoneyTransferParamsV1, MoneyUnstakeParamsV1, Output},
MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1,
MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
@@ -412,10 +415,12 @@ impl ConsensusTestHarness {
pub fn stake_native(
&mut self,
holder: Holder,
epoch: u64,
owncoin: OwnCoin,
) -> Result<(Transaction, ConsensusStakeParamsV1)> {
) -> Result<(Transaction, ConsensusStakeParamsV1, SecretKey)> {
let wallet = self.holders.get_mut(&holder).unwrap();
let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
let (mint_pk, mint_zkbin) =
self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Stake).unwrap();
let timer = Instant::now();
@@ -443,18 +448,19 @@ impl ConsensusTestHarness {
// Building Consensus::Stake params
let consensus_stake_call_debris = ConsensusStakeCallBuilder {
coin: owncoin,
recipient: wallet.keypair.public,
epoch,
value_blind: money_stake_value_blind,
token_blind: money_stake_params.token_blind,
nullifier: money_stake_params.input.nullifier,
merkle_root: money_stake_params.input.merkle_root,
signature_public: money_stake_params.input.signature_public,
mint_zkbin: mint_zkbin.clone(),
mint_pk: mint_pk.clone(),
}
.build()?;
let (consensus_stake_params, consensus_stake_proofs) =
(consensus_stake_call_debris.params, consensus_stake_call_debris.proofs);
let (consensus_stake_params, consensus_stake_proofs, consensus_stake_secret_key) = (
consensus_stake_call_debris.params,
consensus_stake_call_debris.proofs,
consensus_stake_call_debris.signature_secret,
);
// Building stake tx
let mut data = vec![MoneyFunction::StakeV1 as u8];
@@ -469,7 +475,7 @@ impl ConsensusTestHarness {
let proofs = vec![money_stake_proofs, consensus_stake_proofs];
let mut stake_tx = Transaction { calls, proofs, signatures: vec![] };
let money_sigs = stake_tx.create_sigs(&mut OsRng, &[money_stake_secret_key])?;
let consensus_sigs = stake_tx.create_sigs(&mut OsRng, &[money_stake_secret_key])?;
let consensus_sigs = stake_tx.create_sigs(&mut OsRng, &[consensus_stake_secret_key])?;
stake_tx.signatures = vec![money_sigs, consensus_sigs];
tx_action_benchmark.creation_times.push(timer.elapsed());
@@ -481,7 +487,7 @@ impl ConsensusTestHarness {
let size = ::std::mem::size_of_val(&*base58);
tx_action_benchmark.broadcasted_sizes.push(size);
Ok((stake_tx, consensus_stake_params))
Ok((stake_tx, consensus_stake_params, consensus_stake_secret_key))
}
pub async fn execute_stake_native_tx(

View File

@@ -43,6 +43,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
// Slot to verify against
let current_slot = 0;
let current_epoch = 0;
// Initialize harness
let mut th = ConsensusTestHarness::new().await?;
@@ -65,13 +66,14 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
th.assert_trees();
// Gather new owncoin
let alice_oc = th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), false)?;
let alice_oc = th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), None)?;
// Now Alice can stake her owncoin
info!(target: "consensus", "[Alice] =================");
info!(target: "consensus", "[Alice] Building stake tx");
info!(target: "consensus", "[Alice] =================");
let (stake_tx, stake_params) = th.stake_native(Holder::Alice, alice_oc.clone())?;
let (stake_tx, stake_params, stake_secret_key) =
th.stake_native(Holder::Alice, current_epoch, alice_oc.clone())?;
info!(target: "consensus", "[Faucet] ========================");
info!(target: "consensus", "[Faucet] Executing Alice stake tx");
@@ -87,48 +89,51 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
th.assert_trees();
// Gather new staked owncoin
let alice_staked_oc = th.gather_owncoin(Holder::Alice, stake_params.output, true)?;
let alice_staked_oc =
th.gather_consensus_owncoin(Holder::Alice, stake_params.output, Some(stake_secret_key))?;
// Verify values match
assert!(alice_oc.note.value == alice_staked_oc.note.value);
/*
// We simulate the proposal of genesis slot
let slot_checkpoint = th.get_slot_checkpoints_by_slot(current_slot).await?;
// We simulate the proposal of genesis slot
let slot_checkpoint = th.get_slot_checkpoints_by_slot(current_slot).await?;
// With alice's current coin value she can become the slot proposer,
// so she creates a proposal transaction to burn her staked coin,
// reward herself and mint the new coin.
info!(target: "consensus", "[Alice] ====================");
info!(target: "consensus", "[Alice] Building proposal tx");
info!(target: "consensus", "[Alice] ====================");
let (proposal_tx, proposal_params) =
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
// With alice's current coin value she can become the slot proposer,
// so she creates a proposal transaction to burn her staked coin,
// reward herself and mint the new coin.
info!(target: "consensus", "[Alice] ====================");
info!(target: "consensus", "[Alice] Building proposal tx");
info!(target: "consensus", "[Alice] ====================");
let (proposal_tx, proposal_params) =
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
info!(target: "consensus", "[Faucet] ===========================");
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
info!(target: "consensus", "[Faucet] ===========================");
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
.await?;
info!(target: "consensus", "[Faucet] ===========================");
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
info!(target: "consensus", "[Faucet] ===========================");
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
.await?;
info!(target: "consensus", "[Alice] ===========================");
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
info!(target: "consensus", "[Alice] ===========================");
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
info!(target: "consensus", "[Alice] ===========================");
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
info!(target: "consensus", "[Alice] ===========================");
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
th.assert_trees();
th.assert_trees();
// Gather new staked owncoin which includes the reward
let alice_rewarded_staked_oc =
th.gather_owncoin(Holder::Alice, proposal_params.output, true)?;
// Gather new staked owncoin which includes the reward
let alice_rewarded_staked_oc =
th.gather_owncoin(Holder::Alice, proposal_params.output, true)?;
// Verify values match
assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
// Verify values match
assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
*/
let alice_rewarded_staked_oc = alice_staked_oc;
// Now Alice can unstake her owncoin
info!(target: "consensus", "[Alice] ===================");
info!(target: "consensus", "[Alice] Building unstake tx");
info!(target: "consensus", "[Alice] ===================");
let (unstake_tx, unstake_params) =
let (unstake_tx, unstake_params, unstake_secret_key) =
th.unstake_native(Holder::Alice, alice_rewarded_staked_oc.clone())?;
info!(target: "consensus", "[Faucet] ==========================");
@@ -145,7 +150,8 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
th.assert_trees();
// Gather new unstaked owncoin
let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, false)?;
let alice_unstaked_oc =
th.gather_owncoin(Holder::Alice, unstake_params.output, Some(unstake_secret_key))?;
// Verify values match
assert!(alice_rewarded_staked_oc.note.value == alice_unstaked_oc.note.value);

View File

@@ -27,11 +27,13 @@
//! are able to abstract away any wallet interfaces to client implementations.
use darkfi_sdk::{
crypto::{Coin, MerklePosition, Nullifier, SecretKey, TokenId},
crypto::{Coin, MerklePosition, Nullifier, SecretKey, TokenId, DARK_TOKEN_ID},
pasta::pallas,
};
use darkfi_serial::{SerialDecodable, SerialEncodable};
use crate::model::{PALLAS_ZERO, SCALAR_ZERO};
/// `Money::TransferV1` API
pub mod transfer_v1;
@@ -131,3 +133,61 @@ pub struct OwnCoin {
/// Coin's leaf position in the Merkle tree of coins
pub leaf_position: MerklePosition,
}
/// `ConsensusNote` holds the inner attributes of a `Coin`.
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusNote {
/// Serial number of the coin, used for the nullifier
pub serial: pallas::Base,
/// Value of the coin
pub value: u64,
/// Epoch the coin was minted
pub epoch: u64,
/// Blinding factor for the coin bulla
pub coin_blind: pallas::Base,
/// Blinding factor for the value pedersen commitment
pub value_blind: pallas::Scalar,
}
impl From<ConsensusNote> for MoneyNote {
fn from(consensus_note: ConsensusNote) -> Self {
MoneyNote {
serial: consensus_note.serial,
value: consensus_note.value,
token_id: *DARK_TOKEN_ID,
spend_hook: PALLAS_ZERO,
user_data: PALLAS_ZERO,
coin_blind: consensus_note.coin_blind,
value_blind: consensus_note.value_blind,
token_blind: SCALAR_ZERO,
memo: vec![],
}
}
}
/// `ConsensusOwnCoin` is a representation of `Coin` with its respective metadata.
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusOwnCoin {
/// The coin hash
pub coin: Coin,
/// The attached `ConsensusNote`
pub note: ConsensusNote,
/// Coin's secret key
pub secret: SecretKey,
/// Coin's nullifier
pub nullifier: Nullifier,
/// Coin's leaf position in the Merkle tree of coins
pub leaf_position: MerklePosition,
}
impl From<ConsensusOwnCoin> for OwnCoin {
fn from(consensus_own_coin: ConsensusOwnCoin) -> Self {
OwnCoin {
coin: consensus_own_coin.coin,
note: consensus_own_coin.note.into(),
secret: consensus_own_coin.secret,
nullifier: consensus_own_coin.nullifier,
leaf_position: consensus_own_coin.leaf_position,
}
}
}

View File

@@ -35,8 +35,8 @@ use log::{debug, info};
use rand::rngs::OsRng;
use crate::{
client::{MoneyNote, OwnCoin},
model::{MoneyUnstakeParamsV1, Output, StakeInput},
client::{ConsensusOwnCoin, MoneyNote},
model::{ConsensusInput, MoneyUnstakeParamsV1, Output, PALLAS_ZERO, SCALAR_ZERO},
};
pub struct MoneyUnstakeCallDebris {
@@ -75,8 +75,8 @@ pub struct TransactionBuilderOutputInfo {
/// Struct holding necessary information to build a `Money::UnstakeV1` contract call.
pub struct MoneyUnstakeCallBuilder {
/// `OwnCoin` we're given to use in this builder
pub coin: OwnCoin,
/// `ConsensusOwnCoin` we're given to use in this builder
pub coin: ConsensusOwnCoin,
/// Blinding factor for value commitment
pub value_blind: pallas::Scalar,
/// Revealed nullifier
@@ -95,20 +95,19 @@ impl MoneyUnstakeCallBuilder {
pub fn build(&self) -> Result<MoneyUnstakeCallDebris> {
debug!("Building Money::UnstakeV1 contract call");
assert!(self.coin.note.value != 0);
assert!(self.coin.note.token_id == *DARK_TOKEN_ID);
debug!("Building anonymous output");
let output = TransactionBuilderOutputInfo {
value: self.coin.note.value,
token_id: self.coin.note.token_id,
token_id: *DARK_TOKEN_ID,
public_key: self.signature_public,
};
debug!("Finished building output");
let serial = pallas::Base::random(&mut OsRng);
let spend_hook = pallas::Base::zero();
let user_data_enc = pallas::Base::zero();
let token_blind = pallas::Scalar::random(&mut OsRng);
let spend_hook = PALLAS_ZERO;
let user_data_enc = PALLAS_ZERO;
let token_blind = SCALAR_ZERO;
let coin_blind = pallas::Base::random(&mut OsRng);
info!("Creating unstake mint proof for output");
@@ -146,8 +145,8 @@ impl MoneyUnstakeCallBuilder {
note: encrypted_note,
};
let input = StakeInput {
token_blind,
let input = ConsensusInput {
epoch: self.coin.note.epoch,
value_commit: public_inputs.value_commit,
nullifier: self.nullifier,
merkle_root: self.merkle_root,

View File

@@ -31,7 +31,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
error::MoneyError,
model::{ConsensusStakeParamsV1, MoneyStakeParamsV1, MoneyStakeUpdateV1},
model::{ConsensusStakeParamsV1, MoneyStakeParamsV1, MoneyStakeUpdateV1, PALLAS_ZERO},
MoneyFunction, MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
MONEY_CONTRACT_ZKAS_BURN_NS_V1,
};
@@ -137,7 +137,7 @@ pub(crate) fn money_stake_process_instruction_v1(
}
// If spend hook is set, check its correctness
if input.spend_hook != pallas::Base::zero() && next.contract_id.inner() != input.spend_hook {
if input.spend_hook != PALLAS_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())
}
@@ -148,7 +148,7 @@ pub(crate) fn money_stake_process_instruction_v1(
return Err(MoneyError::NextCallFunctionMissmatch.into())
}
// Verify next call StakeInput is the same as this calls input
// Verify next call ConsensusInput is the same as this calls input
let next_params: ConsensusStakeParamsV1 = deserialize(&next.data[1..])?;
if input != &next_params.input {
msg!("[MoneyStakeV1] Error: Next call input mismatch");

View File

@@ -20,16 +20,14 @@ use darkfi_sdk::{
crypto::ContractId,
db::{db_contains_key, db_lookup},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
msg, ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use super::transfer_v1::{money_transfer_get_metadata_v1, money_transfer_process_update_v1};
use crate::{
error::MoneyError,
model::{MoneyTransferParamsV1, MoneyTransferUpdateV1},
model::{MoneyTransferParamsV1, MoneyTransferUpdateV1, PALLAS_ZERO},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
MONEY_CONTRACT_NULLIFIERS_TREE,
};
@@ -112,7 +110,7 @@ pub(crate) fn money_otcswap_process_instruction_v1(
// For now, make sure that the inputs' spend hooks are zero.
// This should however be allowed to some extent, e.g. if we
// want a DAO to be able to do an atomic swap.
if input.spend_hook != pallas::Base::zero() {
if input.spend_hook != PALLAS_ZERO {
msg!("[OtcSwapV1] Error: Unable to swap coins with spend_hook != 0 (input {})", i);
return Err(MoneyError::SpendHookNonZero.into())
}

View File

@@ -31,7 +31,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
error::MoneyError,
model::{MoneyTransferParamsV1, MoneyTransferUpdateV1},
model::{MoneyTransferParamsV1, MoneyTransferUpdateV1, PALLAS_ZERO},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_FAUCET_PUBKEYS, MONEY_CONTRACT_INFO_TREE,
MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
@@ -193,7 +193,7 @@ pub(crate) fn money_transfer_process_instruction_v1(
}
// If spend hook is set, check its correctness
if input.spend_hook != pallas::Base::zero() {
if input.spend_hook != PALLAS_ZERO {
let next_call_idx = call_idx + 1;
if next_call_idx >= calls.len() as u32 {
msg!("[TransferV1] Error: next_call_idx out of bounds (input {})", i);

View File

@@ -31,7 +31,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
error::MoneyError,
model::{ConsensusUnstakeParamsV1, MoneyUnstakeParamsV1, MoneyUnstakeUpdateV1},
model::{ConsensusUnstakeParamsV1, MoneyUnstakeParamsV1, MoneyUnstakeUpdateV1, PALLAS_ZERO},
MoneyFunction, CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
@@ -100,8 +100,12 @@ pub(crate) fn money_unstake_process_instruction_v1(
let input = &params.input;
let output = &params.output;
// Only native token can be unstaked
if output.token_commit != pedersen_commitment_base(DARK_TOKEN_ID.inner(), input.token_blind) {
// Only native token can be unstaked.
// Since consensus coins don't have token commitments or blinds,
// we use zero as the token blind of newlly minded token
if output.token_commit !=
pedersen_commitment_base(DARK_TOKEN_ID.inner(), pallas::Scalar::zero())
{
msg!("[MoneyUnstakeV1] Error: Input used non-native token");
return Err(MoneyError::StakeInputNonNativeToken.into())
}
@@ -153,7 +157,7 @@ pub(crate) fn money_unstake_process_instruction_v1(
}
// If next spend hook is set, check its correctness
if params.spend_hook != pallas::Base::zero() {
if params.spend_hook != PALLAS_ZERO {
let next_call_idx = call_idx + 1;
if next_call_idx >= calls.len() as u32 {
msg!("[MoneyUnstakeV1] Error: next_call_idx out of bounds");

View File

@@ -60,33 +60,9 @@ pub struct Input {
pub signature_public: PublicKey,
}
/// Anonymous input for staking contract calls
/// Anonymous input for consensus contract calls
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
pub struct StakeInput {
/// Blinding factor for `token_id`
pub token_blind: pallas::Scalar,
/// Pedersen commitment for the staked coin's value
pub value_commit: pallas::Point,
/// Revealed nullifier
pub nullifier: Nullifier,
/// Revealed Merkle root
pub merkle_root: MerkleNode,
/// Public key for the signature
pub signature_public: PublicKey,
}
impl PartialEq<StakeInput> for Input {
fn eq(&self, other: &StakeInput) -> bool {
self.value_commit == other.value_commit &&
self.nullifier == other.nullifier &&
self.merkle_root == other.merkle_root &&
self.signature_public == other.signature_public
}
}
/// Anonymous input for unstaking contract calls
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
pub struct UnstakeInput {
pub struct ConsensusInput {
/// Epoch the coin was minted
pub epoch: u64,
/// Pedersen commitment for the staked coin's value
@@ -99,12 +75,11 @@ pub struct UnstakeInput {
pub signature_public: PublicKey,
}
impl PartialEq<StakeInput> for UnstakeInput {
fn eq(&self, other: &StakeInput) -> bool {
impl PartialEq<ConsensusInput> for Input {
fn eq(&self, other: &ConsensusInput) -> bool {
self.value_commit == other.value_commit &&
self.nullifier == other.nullifier &&
self.merkle_root == other.merkle_root &&
self.signature_public == other.signature_public
self.merkle_root == other.merkle_root
}
}
@@ -121,6 +96,17 @@ pub struct Output {
pub note: AeadEncryptedNote,
}
/// A consensus contract call's anonymous output
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
pub struct ConsensusOutput {
/// Pedersen commitment for the output's value
pub value_commit: pallas::Point,
/// Minted coin
pub coin: Coin,
/// AEAD encrypted note
pub note: AeadEncryptedNote,
}
/// Parameters for `Money::Transfer` and `Money::OtcSwap`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyTransferParamsV1 {
@@ -193,7 +179,7 @@ pub struct MoneyStakeUpdateV1 {
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyUnstakeParamsV1 {
/// Burnt token revealed info
pub input: StakeInput,
pub input: ConsensusInput,
/// Spend hook used to invoke other contracts.
/// If this value is nonzero then the subsequent contract call in the tx
/// must have this value as its ID.
@@ -217,9 +203,9 @@ pub struct MoneyUnstakeUpdateV1 {
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusStakeParamsV1 {
/// Burnt token revealed info
pub input: StakeInput,
pub input: ConsensusInput,
/// Anonymous output
pub output: Output,
pub output: ConsensusOutput,
}
/// State update for `Consensus::Stake`
@@ -233,7 +219,7 @@ pub struct ConsensusStakeUpdateV1 {
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct ConsensusUnstakeParamsV1 {
/// Anonymous input
pub input: UnstakeInput,
pub input: ConsensusInput,
}
/// State update for `Consensus::Unstake`
@@ -242,3 +228,8 @@ pub struct ConsensusUnstakeUpdateV1 {
/// Revealed nullifier
pub nullifier: Nullifier,
}
// `pallas::Base` used as prefix/suffix in poseidon hash
pub const PALLAS_ZERO: pallas::Base = pallas::Base::zero();
// `pallas::Scalar` used as prefix/suffix in poseidon hash
pub const SCALAR_ZERO: pallas::Scalar = pallas::Scalar::zero();