| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2022 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use std::{any::Any, collections::HashMap, hash::Hasher};
- use lazy_static::lazy_static;
- use log::debug;
- use pasta_curves::{
- group::ff::{Field, PrimeField},
- pallas,
- };
- use rand::rngs::OsRng;
- use darkfi::{
- crypto::{
- keypair::{PublicKey, SecretKey},
- proof::{ProvingKey, VerifyingKey},
- schnorr::{SchnorrPublic, SchnorrSecret, Signature},
- types::DrkCircuitField,
- Proof,
- },
- zk::{vm::ZkCircuit, vm_stack::empty_witnesses},
- zkas::decoder::ZkBinary,
- Error,
- };
- use darkfi_serial::Encodable;
- use crate::error::{DaoError, DaoResult};
- /// Parse pallas::Base from a base58-encoded string
- pub fn parse_b58(s: &str) -> std::result::Result<pallas::Base, darkfi::Error> {
- let bytes = bs58::decode(s).into_vec()?;
- if bytes.len() != 32 {
- return Err(Error::ParseFailed("Failed parsing DrkTokenId from base58 string"))
- }
- let ret = pallas::Base::from_repr(bytes.try_into().unwrap());
- if ret.is_some().unwrap_u8() == 1 {
- return Ok(ret.unwrap())
- }
- Err(Error::ParseFailed("Failed parsing DrkTokenId from base58 string"))
- }
- // The token of the DAO treasury.
- lazy_static! {
- pub static ref DRK_ID: pallas::Base = pallas::Base::random(&mut OsRng);
- }
- // Governance tokens that are airdropped to users to operate the DAO.
- lazy_static! {
- pub static ref GOV_ID: pallas::Base = pallas::Base::random(&mut OsRng);
- }
- #[derive(Eq, PartialEq, Debug)]
- pub struct HashableBase(pub pallas::Base);
- impl std::hash::Hash for HashableBase {
- fn hash<H: Hasher>(&self, state: &mut H) {
- let bytes = self.0.to_repr();
- bytes.hash(state);
- }
- }
- #[derive(Clone)]
- pub struct ZkBinaryContractInfo {
- pub k_param: u32,
- pub bincode: ZkBinary,
- pub proving_key: ProvingKey,
- pub verifying_key: VerifyingKey,
- }
- #[derive(Clone)]
- pub struct ZkNativeContractInfo {
- pub proving_key: ProvingKey,
- pub verifying_key: VerifyingKey,
- }
- #[derive(Clone)]
- pub enum ZkContractInfo {
- Binary(ZkBinaryContractInfo),
- Native(ZkNativeContractInfo),
- }
- #[derive(Clone)]
- pub struct ZkContractTable {
- // Key will be a hash of zk binary contract on chain
- table: HashMap<String, ZkContractInfo>,
- }
- impl ZkContractTable {
- pub fn new() -> Self {
- Self { table: HashMap::new() }
- }
- pub fn add_contract(&mut self, key: String, bincode: ZkBinary, k_param: u32) {
- let witnesses = empty_witnesses(&bincode);
- let circuit = ZkCircuit::new(witnesses, bincode.clone());
- let proving_key = ProvingKey::build(k_param, &circuit);
- let verifying_key = VerifyingKey::build(k_param, &circuit);
- let info = ZkContractInfo::Binary(ZkBinaryContractInfo {
- k_param,
- bincode,
- proving_key,
- verifying_key,
- });
- self.table.insert(key, info);
- }
- pub fn add_native(
- &mut self,
- key: String,
- proving_key: ProvingKey,
- verifying_key: VerifyingKey,
- ) {
- self.table.insert(
- key,
- ZkContractInfo::Native(ZkNativeContractInfo { proving_key, verifying_key }),
- );
- }
- pub fn lookup(&self, key: &String) -> Option<&ZkContractInfo> {
- self.table.get(key)
- }
- }
- // ANCHOR: transaction
- pub struct Transaction {
- pub func_calls: Vec<FuncCall>,
- // TODO: this is wrong. It should be Vec<Vec<Signature>>
- // each Vec<Signature> correspond to ONE function call
- pub signatures: Vec<Signature>,
- }
- // ANCHOR_END: transaction
- impl Transaction {
- /// Verify ZK contracts for the entire tx
- /// In real code, we could parallelize this for loop
- /// TODO: fix use of unwrap with Result type stuff
- pub fn zk_verify(&self, zk_bins: &ZkContractTable) -> DaoResult<()> {
- for func_call in &self.func_calls {
- let proofs_public_vals = &func_call.call_data.zk_public_values();
- assert_eq!(
- proofs_public_vals.len(),
- func_call.proofs.len(),
- "proof_public_vals.len()={} and func_call.proofs.len()={} do not match",
- proofs_public_vals.len(),
- func_call.proofs.len()
- );
- for (i, (proof, (key, public_vals))) in
- func_call.proofs.iter().zip(proofs_public_vals.iter()).enumerate()
- {
- match zk_bins.lookup(key).unwrap() {
- ZkContractInfo::Binary(info) => {
- let verifying_key = &info.verifying_key;
- let verify_result = proof.verify(&verifying_key, public_vals);
- if verify_result.is_err() {
- return Err(DaoError::VerifyProofFailed(i, key.to_string()))
- }
- //assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
- }
- ZkContractInfo::Native(info) => {
- let verifying_key = &info.verifying_key;
- let verify_result = proof.verify(&verifying_key, public_vals);
- if verify_result.is_err() {
- return Err(DaoError::VerifyProofFailed(i, key.to_string()))
- }
- //assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
- }
- };
- debug!(target: "demo", "zk_verify({}) passed [i={}]", key, i);
- }
- }
- Ok(())
- }
- pub fn verify_sigs(&self) {
- let mut unsigned_tx_data = vec![];
- for (i, (func_call, signature)) in
- self.func_calls.iter().zip(self.signatures.clone()).enumerate()
- {
- func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
- let signature_pub_keys = func_call.call_data.signature_public_keys();
- for signature_pub_key in signature_pub_keys {
- let verify_result = signature_pub_key.verify(&unsigned_tx_data[..], &signature);
- assert!(verify_result, "verify sigs[{}] failed", i);
- }
- debug!(target: "demo", "verify_sigs({}) passed", i);
- }
- }
- }
- pub fn sign(signature_secrets: Vec<SecretKey>, func_calls: &Vec<FuncCall>) -> Vec<Signature> {
- let mut signatures = vec![];
- let mut unsigned_tx_data = vec![];
- for (_i, (signature_secret, func_call)) in
- signature_secrets.iter().zip(func_calls.iter()).enumerate()
- {
- func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
- let signature = signature_secret.sign(&unsigned_tx_data[..]);
- signatures.push(signature);
- }
- signatures
- }
- type ContractId = pallas::Base;
- type FuncId = pallas::Base;
- // ANCHOR: funccall
- pub struct FuncCall {
- pub contract_id: ContractId,
- pub func_id: FuncId,
- pub call_data: Box<dyn CallDataBase + Send + Sync>,
- pub proofs: Vec<Proof>,
- }
- // ANCHOR_END: funccall
- impl Encodable for FuncCall {
- fn encode<W: std::io::Write>(&self, mut w: W) -> std::result::Result<usize, std::io::Error> {
- let mut len = 0;
- len += self.contract_id.encode(&mut w)?;
- len += self.func_id.encode(&mut w)?;
- len += self.proofs.encode(&mut w)?;
- len += self.call_data.encode_bytes(&mut w)?;
- Ok(len)
- }
- }
- // ANCHOR: calldatabase_trait
- pub trait CallDataBase {
- // Public values for verifying the proofs
- // Needed so we can convert internal types so they can be used in Proof::verify()
- fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)>;
- // For upcasting to CallData itself so it can be read in state_transition()
- fn as_any(&self) -> &dyn Any;
- // Public keys we will use to verify transaction signatures.
- fn signature_public_keys(&self) -> Vec<PublicKey>;
- fn encode_bytes(
- &self,
- writer: &mut dyn std::io::Write,
- ) -> std::result::Result<usize, std::io::Error>;
- }
- // ANCHOR_END: calldatabase_trait
- type GenericContractState = Box<dyn Any + Send>;
- pub struct StateRegistry {
- pub states: HashMap<HashableBase, GenericContractState>,
- }
- impl StateRegistry {
- pub fn new() -> Self {
- Self { states: HashMap::new() }
- }
- pub fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
- debug!(target: "StateRegistry::register()", "contract_id: {:?}", contract_id);
- self.states.insert(HashableBase(contract_id), state);
- }
- pub fn lookup_mut<'a, S: 'static>(&'a mut self, contract_id: ContractId) -> Option<&'a mut S> {
- self.states.get_mut(&HashableBase(contract_id)).and_then(|state| state.downcast_mut())
- }
- pub fn lookup<'a, S: 'static>(&'a self, contract_id: ContractId) -> Option<&'a S> {
- self.states.get(&HashableBase(contract_id)).and_then(|state| state.downcast_ref())
- }
- }
- pub trait UpdateBase {
- fn apply(self: Box<Self>, states: &mut StateRegistry);
- }
|