add leo-state module

This commit is contained in:
collin 2020-08-11 23:51:56 -07:00
parent 3980ff8e1e
commit 89d76688d7
14 changed files with 1938 additions and 64 deletions

1442
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,13 +13,14 @@ name = "leo"
path = "leo/main.rs"
[workspace]
members = [ "ast", "compiler", "gadgets", "input", "linter", "package", "typed" ]
members = [ "ast", "compiler", "gadgets", "input", "linter", "package", "typed", "state"]
[dependencies]
leo-compiler = { path = "compiler", version = "0.1.0" }
leo-gadgets = { path = "gadgets", version = "0.1.0" }
leo-input = { path = "input", version = "0.1.0" }
leo-package = { path = "package", version = "0.1.0" }
leo-state = { path = "state", version = "0.1.0" }
snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-algorithms", default-features = false }
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-curves", default-features = false }

25
state/Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
[package]
name = "leo-state"
version = "0.1.0"
authors = ["The Aleo Team <hello@aleo.org>"]
edition = "2018"
[dependencies]
leo-input = { path = "../input", version = "0.1.0" }
leo-typed = { path = "../typed", version = "0.1.0" }
snarkos-algorithms = { path = "../../snarkOS/algorithms" }
snarkos-curves = { path = "../../snarkOS/curves" }
snarkos-dpc = { path = "../../snarkOS/dpc" }
snarkos-errors = { path = "../../snarkOS/errors" }
snarkos-models = { path = "../../snarkOS/models" }
snarkos-objects = { path = "../../snarkOS/objects" }
snarkos-utilities = { path = "../../snarkOS/utilities" }
rand = { version = "0.7" }
rand_xorshift = { version = "0.2" }
thiserror = { version = "1.0" }
[dev-dependencies]
snarkos-testing = { path = "../../snarkOS/testing" }

View File

@ -0,0 +1,5 @@
//
// #[derive(Debug, Error)]
// pub enum VerifyError {
//
// }

5
state/src/errors/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod error;
pub use self::error::*;
pub mod record_verification_error;
pub use self::record_verification_error::*;

View File

@ -0,0 +1,30 @@
use snarkos_errors::{algorithms::CommitmentError, objects::account::AccountError};
use std::{io::Error as IOError, num::ParseIntError, str::ParseBoolError};
#[derive(Debug, Error)]
pub enum RecordVerificationError {
#[error("{}", _0)]
AccountError(#[from] AccountError),
#[error("{}", _0)]
CommitmentError(#[from] CommitmentError),
#[error("expected parameter array of u8 bytes, found `{}`", _0)]
ExpectedBytes(String),
#[error("expected integer parameter, found `{}`", _0)]
ExpectedInteger(String),
#[error("{}", _0)]
IOError(#[from] IOError),
#[error("record parameter `{}` not found in state file", _0)]
MissingParameter(String),
#[error("{}", _0)]
ParseBoolError(#[from] ParseBoolError),
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
}

11
state/src/lib.rs Normal file
View File

@ -0,0 +1,11 @@
#[macro_use]
extern crate thiserror;
pub mod errors;
pub use self::errors::*;
pub mod local_data_commitment;
pub use self::local_data_commitment::*;
pub mod record_commitment;
pub use self::record_commitment::*;

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,123 @@
use crate::RecordVerificationError;
use leo_typed::{InputValue, Record as TypedRecord};
use snarkos_dpc::base_dpc::instantiated::Components;
use snarkos_objects::AccountAddress;
use std::{convert::TryFrom, str::FromStr};
static OWNER_PARAMETER_STRING: &str = "owner";
static IS_DUMMY_PARAMETER_STRING: &str = "is_dummy";
static VALUE_PARAMETER_STRING: &str = "value";
static PAYLOAD_PARAMETER_STRING: &str = "parameter";
static BIRTH_PROGRAM_ID_PARAMETER_STRING: &str = "birth_program_id";
static DEATH_PROGRAM_ID_PARAMETER_STRING: &str = "death_program_id";
static SERIAL_NUMBER_NONCE_PARAMETER_STRING: &str = "serial_number_nonce";
static COMMITMENT_PARAMETER_STRING: &str = "commitment";
static COMMITMENT_RANDOMNESS_PARAMETER_STRING: &str = "commitment_randomness";
pub struct DPCRecordValues {
pub owner: AccountAddress<Components>,
pub is_dummy: bool,
pub value: u64,
pub payload: Vec<u8>,
pub birth_program_id: Vec<u8>,
pub death_program_id: Vec<u8>,
pub serial_number_nonce: Vec<u8>,
pub commitment: Vec<u8>,
pub commitment_randomness: Vec<u8>,
}
impl TryFrom<TypedRecord> for DPCRecordValues {
type Error = RecordVerificationError;
fn try_from(record: TypedRecord) -> Result<Self, Self::Error> {
// Lookup record owner
let owner_value = get_parameter_value(OWNER_PARAMETER_STRING.to_owned(), &record)?;
let owner = AccountAddress::<Components>::from_str(&format!("{}", owner_value))?;
// Lookup record is_dummy
let is_dummy_value = get_parameter_value(IS_DUMMY_PARAMETER_STRING.to_owned(), &record)?;
let is_dummy = is_dummy_value.to_string().parse::<bool>()?;
// Lookup record value
let value_value = get_parameter_value(VALUE_PARAMETER_STRING.to_owned(), &record)?;
let value = input_to_integer_string(value_value)?.parse::<u64>()?;
// Lookup record payload
let payload_value = get_parameter_value(PAYLOAD_PARAMETER_STRING.to_owned(), &record)?;
let payload = input_to_u8_vec(payload_value)?;
// Lookup record birth program id
let birth_program_id_value = get_parameter_value(BIRTH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &record)?;
let birth_program_id = input_to_u8_vec(birth_program_id_value)?;
// Lookup record death program id
let death_program_id_value = get_parameter_value(DEATH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &record)?;
let death_program_id = input_to_u8_vec(death_program_id_value)?;
// Lookup record serial number nonce
let serial_number_nonce_value = get_parameter_value(SERIAL_NUMBER_NONCE_PARAMETER_STRING.to_owned(), &record)?;
let serial_number_nonce = input_to_u8_vec(serial_number_nonce_value)?;
// Lookup record commitment
let commitment_value = get_parameter_value(COMMITMENT_PARAMETER_STRING.to_owned(), &record)?;
let commitment = input_to_u8_vec(commitment_value)?;
// Lookup record commitment randomness
let commitment_randomness_value =
get_parameter_value(COMMITMENT_RANDOMNESS_PARAMETER_STRING.to_owned(), &record)?;
let commitment_randomness = input_to_u8_vec(commitment_randomness_value)?;
Ok(Self {
owner,
is_dummy,
value,
payload,
birth_program_id,
death_program_id,
serial_number_nonce,
commitment,
commitment_randomness,
})
}
}
fn get_parameter_value(name: String, record: &TypedRecord) -> Result<InputValue, RecordVerificationError> {
let parameters = record.values();
let matched_parameter = parameters
.iter()
.find(|(parameter, _value)| parameter.variable.name == name);
match matched_parameter {
Some((_parameter, value_option)) => match value_option {
Some(value) => Ok(value.clone()),
None => Err(RecordVerificationError::MissingParameter(name)),
},
None => Err(RecordVerificationError::MissingParameter(name)),
}
}
fn input_to_integer_string(input: InputValue) -> Result<String, RecordVerificationError> {
match input {
InputValue::Integer(_type, string) => Ok(string),
value => Err(RecordVerificationError::ExpectedInteger(value.to_string())),
}
}
fn input_to_u8_vec(input: InputValue) -> Result<Vec<u8>, RecordVerificationError> {
let input_array = match input {
InputValue::Array(values) => values,
value => return Err(RecordVerificationError::ExpectedBytes(value.to_string())),
};
let mut result_vec = vec![];
for input in input_array {
let integer_string = input_to_integer_string(input)?;
let byte = integer_string.parse::<u8>()?;
result_vec.push(byte);
}
Ok(result_vec)
}

View File

@ -0,0 +1,5 @@
pub mod dpc_record_values;
pub use self::dpc_record_values::*;
pub mod verify_record_commitment;
pub use self::verify_record_commitment::*;

View File

@ -0,0 +1,35 @@
use crate::{DPCRecordValues, RecordVerificationError};
use leo_typed::Record as TypedRecord;
use snarkos_dpc::base_dpc::instantiated::RecordCommitment;
use snarkos_models::{algorithms::CommitmentScheme, curves::Fp256};
use snarkos_utilities::{bytes::ToBytes, to_bytes, FromBytes};
use std::convert::TryFrom;
pub fn verify_record_commitment(
typed_record: TypedRecord,
record_commitment: RecordCommitment,
) -> Result<bool, RecordVerificationError> {
// generate a dpc record from the typed record
let record = DPCRecordValues::try_from(typed_record)?;
let record_commitment_input = to_bytes![
record.owner,
record.is_dummy,
record.value,
record.payload,
record.birth_program_id,
record.death_program_id,
record.serial_number_nonce
]?;
let commitment = Fp256::read(&record.commitment[..])?;
let commitment_randomness = Fp256::read(&record.commitment_randomness[..])?;
let record_commitment =
RecordCommitment::commit(&record_commitment, &record_commitment_input, &commitment_randomness)?;
let result = record_commitment == commitment;
Ok(result)
}

1
state/tests/mod.rs Normal file
View File

@ -0,0 +1 @@
// mod test;

316
state/tests/test.rs Normal file
View File

@ -0,0 +1,316 @@
use snarkos_curves::edwards_bls12::{EdwardsParameters, EdwardsProjective as EdwardsBls};
use snarkos_dpc::base_dpc::{
instantiated::*,
record_encryption::*,
record_payload::RecordPayload,
record_serializer::*,
BaseDPCComponents,
ExecuteContext,
DPC,
};
use snarkos_models::{
algorithms::{CommitmentScheme, CRH},
dpc::{Record, RecordSerializerScheme},
objects::AccountScheme,
};
use snarkos_objects::{
Account,
AccountViewKey,
Block,
BlockHeader,
BlockHeaderHash,
DPCTransactions,
MerkleRootHash,
PedersenMerkleRootHash,
ProofOfSuccinctWork,
};
use snarkos_utilities::{bytes::ToBytes, rand::UniformRand, to_bytes};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use snarkos_algorithms::commitment_tree::CommitmentMerklePath;
use snarkos_dpc::{DummyProgram, NoopProgram};
use snarkos_models::{
algorithms::MerkleParameters,
dpc::{DPCScheme, Program},
objects::LedgerScheme,
};
#[test]
fn test_integrate_with_dpc() {
use snarkos_testing::storage::*;
type L = Ledger<Tx, CommitmentMerkleParameters>;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
// Specify network_id
let network_id: u8 = 0;
// Generate parameters for the ledger, commitment schemes, CRH, and the
// "always-accept" program.
let ledger_parameters = CommitmentMerkleParameters::setup(&mut rng);
let system_parameters = InstantiatedDPC::generate_system_parameters(&mut rng).unwrap();
let noop_program_snark_pp =
InstantiatedDPC::generate_noop_program_snark_parameters(&system_parameters, &mut rng).unwrap();
let dummy_program_snark_pp =
InstantiatedDPC::generate_dummy_program_snark_parameters(&system_parameters, &mut rng).unwrap();
let noop_program_id = to_bytes![
ProgramVerificationKeyHash::hash(
&system_parameters.program_verification_key_hash,
&to_bytes![noop_program_snark_pp.verification_key].unwrap()
)
.unwrap()
]
.unwrap();
let dummy_program_id = to_bytes![
ProgramVerificationKeyHash::hash(
&system_parameters.program_verification_key_hash,
&to_bytes![dummy_program_snark_pp.verification_key].unwrap()
)
.unwrap()
]
.unwrap();
let signature_parameters = &system_parameters.account_signature;
let commitment_parameters = &system_parameters.account_commitment;
let encryption_parameters = &system_parameters.account_encryption;
// Generate metadata and an account for a dummy initial record.
let dummy_account = Account::new(
signature_parameters,
commitment_parameters,
encryption_parameters,
&mut rng,
)
.unwrap();
let genesis_block = Block {
header: BlockHeader {
previous_block_hash: BlockHeaderHash([0u8; 32]),
merkle_root_hash: MerkleRootHash([0u8; 32]),
time: 0,
difficulty_target: 0x07FF_FFFF_FFFF_FFFF_u64,
nonce: 0,
pedersen_merkle_root_hash: PedersenMerkleRootHash([0u8; 32]),
proof: ProofOfSuccinctWork::default(),
},
transactions: DPCTransactions::new(),
};
// Use genesis record, serial number, and memo to initialize the ledger.
let ledger = initialize_test_blockchain::<Tx, CommitmentMerkleParameters>(ledger_parameters, genesis_block);
let sn_nonce = SerialNumberNonce::hash(&system_parameters.serial_number_nonce, &[0u8; 1]).unwrap();
// let old_record = DPC::generate_record(
// &system_parameters,
// &sn_nonce,
// &dummy_account.address,
// true,
// 0,
// &RecordPayload::default(),
// &dummy_program_id,
// &dummy_program_id,
// &mut rng,
// )
// .unwrap();
let value = rng.gen();
let payload: [u8; 32] = rng.gen();
let old_record = DPC::generate_record(
&system_parameters,
&sn_nonce,
&dummy_account.address,
false,
value,
&RecordPayload::from_bytes(&payload),
&noop_program_id,
&noop_program_id,
&mut rng,
)
.unwrap();
// Set the input records for our transaction to be the initial dummy records.
let old_records = vec![old_record.clone(); NUM_INPUT_RECORDS];
let old_account_private_keys = vec![dummy_account.private_key.clone(); NUM_INPUT_RECORDS];
// Construct new records.
// Create an account for an actual new record.
let new_account = Account::new(
signature_parameters,
commitment_parameters,
encryption_parameters,
&mut rng,
)
.unwrap();
// Set the new record's program to be the "always-accept" program.
let new_record_owners = vec![new_account.address.clone(); NUM_OUTPUT_RECORDS];
let new_is_dummy_flags = vec![false; NUM_OUTPUT_RECORDS];
let new_values = vec![10; NUM_OUTPUT_RECORDS];
let new_payloads = vec![RecordPayload::default(); NUM_OUTPUT_RECORDS];
let new_birth_program_ids = vec![noop_program_id.clone(); NUM_OUTPUT_RECORDS];
let new_death_program_ids = vec![noop_program_id.clone(); NUM_OUTPUT_RECORDS];
let memo = [0u8; 32];
let context = <InstantiatedDPC as DPCScheme<L>>::execute_offline(
&system_parameters,
&old_records,
&old_account_private_keys,
&new_record_owners,
&new_is_dummy_flags,
&new_values,
&new_payloads,
&new_birth_program_ids,
&new_death_program_ids,
&memo,
network_id,
&mut rng,
)
.unwrap();
let local_data = context.into_local_data();
for (i, record) in local_data.old_records.iter().enumerate() {
println!("{} : {}", i, record.is_dummy());
}
//////////////////////////////////////////////////////////////
// Todo: parse state from file instead of DPC::generate_record
// compare commitments
/*
let commitment = Commit(
record.owner,
record.value,
record.payload,
record.is_dummy,
record.birth_program_id,
record.death_program_id,
record.serial_number_nonce,
record.commitment_randomness,
);
record.commitment == commitment
*/
let record_commitment_input = to_bytes![
old_record.owner(),
old_record.is_dummy(),
old_record.value(),
old_record.payload(),
old_record.birth_program_id(),
old_record.death_program_id(),
old_record.serial_number_nonce()
]
.unwrap();
let record_commitment = RecordCommitment::commit(
&system_parameters.record_commitment,
&record_commitment_input,
&old_record.commitment_randomness(),
)
.unwrap();
assert_eq!(record_commitment, old_record.commitment());
//////////////////////////////////////////////////////////////
// Verify local data commitment
// let leaf_index = 0;
// let root = local_data.local_data_merkle_tree.root();
//
// let path = ledger.prove_cm(&old_record.commitment()).unwrap();
// let memo = local_data.memorandum;
// let network_id = local_data.network_id;
// let leaf_randomness = local_data.local_data_commitment_randomizers[0].clone();
// Verify that the local data commitment leaf is valid for the root
// let path = ledger.prove_cm(&record.commitment()).unwrap();
// let digest = ledger.digest().unwrap();
// let verified = path.verify(&digest, &record.commitment()).unwrap();
/////////////////////////////////////////////////
// Generate the program proofs
// let noop_program = NoopProgram::<_, <Components as BaseDPCComponents>::NoopProgramSNARK>::new(noop_program_id);
// let dummy_program = DummyProgram::<_, <Components as BaseDPCComponents>::DummyProgramSNARK>::new(dummy_program_id);
//
// let mut old_proof_and_vk = vec![];
// for i in 0..NUM_INPUT_RECORDS {
// let private_input = dummy_program
// .execute(
// &dummy_program_snark_pp.proving_key,
// &dummy_program_snark_pp.verification_key,
// &local_data,
// i as u8,
// &mut rng,
// )
// .unwrap();
//
// old_proof_and_vk.push(private_input);
// }
//
// let mut new_proof_and_vk = vec![];
// for j in 0..NUM_OUTPUT_RECORDS {
// let private_input = noop_program
// .execute(
// &noop_program_snark_pp.proving_key,
// &noop_program_snark_pp.verification_key,
// &local_data,
// (NUM_INPUT_RECORDS + j) as u8,
// &mut rng,
// )
// .unwrap();
//
// new_proof_and_vk.push(private_input);
// }
//
// let ExecuteContext {
// system_parameters: _,
//
// old_records,
// old_account_private_keys,
// old_serial_numbers,
// old_randomizers: _,
//
// new_records,
// new_sn_nonce_randomness,
// new_commitments,
//
// new_records_encryption_randomness,
// new_encrypted_records: _,
// new_encrypted_record_hashes,
//
// program_commitment,
// program_randomness,
// local_data_merkle_tree,
// local_data_commitment_randomizers,
// value_balance,
// memorandum,
// network_id,
// } = context;
//
// let local_data_root = local_data_merkle_tree.root();
// Verify that the local data commitment leaf is valid for the root
// let local_data_commitment = LocalDataCommitment::commit(
// &system_parameters.local_data_commitment,
//
// )
// let merkle = CommitmentMerklePath::verify(
// system_parameters.local_data_commitment
// state.root
// state.path
// )
// system_parameters.local_data_commitment
}