Skip to content

Commit

Permalink
old, cheap exodus
Browse files Browse the repository at this point in the history
  • Loading branch information
dvush committed Jan 13, 2021
1 parent 9712be4 commit aef22e1
Show file tree
Hide file tree
Showing 23 changed files with 1,328 additions and 613 deletions.
542 changes: 542 additions & 0 deletions contracts/contracts/PlonkCore.sol

Large diffs are not rendered by default.

47 changes: 32 additions & 15 deletions contracts/contracts/Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,66 @@ import "./KeysWithPlonkVerifier.sol";
import "./Config.sol";

// Hardcoded constants to avoid accessing store
contract Verifier is KeysWithPlonkVerifier, Config {
contract Verifier is KeysWithPlonkVerifier, KeysWithPlonkVerifierOld, Config {
function initialize(bytes calldata) external {}

/// @notice Verifier contract upgrade. Can be external because Proxy contract intercepts illegal calls of this function.
/// @param upgradeParameters Encoded representation of upgrade parameters
function upgrade(bytes calldata upgradeParameters) external {}

function verifyAggregatedProof(
function verifyAggregatedBlockProof(
uint256[] memory _recursiveInput,
uint256[] memory _proof,
uint8[] memory _vkIndexes,
uint256[] memory _individual_vks_inputs,
uint256[16] memory _subproofs_limbs,
bool blockProof
uint256[16] memory _subproofs_limbs
) external view returns (bool) {
// #if DUMMY_VERIFIER
if (blockProof) {
uint256 oldGasValue = gasleft();
uint256 tmp;
while (gasleft() + 500000 > oldGasValue) {
tmp += 1;
}
return true;
uint256 oldGasValue = gasleft();
// HACK: ignore warnings from unused variables
abi.encode(_recursiveInput, _proof, _vkIndexes, _individual_vks_inputs, _subproofs_limbs);
uint256 tmp;
while (gasleft() + 500000 > oldGasValue) {
tmp += 1;
}
// #endif
return true;
// #else
for (uint256 i = 0; i < _individual_vks_inputs.length; ++i) {
uint256 commitment = _individual_vks_inputs[i];
_individual_vks_inputs[i] = commitment & INPUT_MASK;
}
VerificationKey memory vk = getVkAggregated(uint32(_vkIndexes.length));

uint256 treeRoot = blockProof ? VK_TREE_ROOT : VK_EXIT_TREE_ROOT;

return
verify_serialized_proof_with_recursion(
_recursiveInput,
_proof,
treeRoot,
VK_TREE_ROOT,
VK_MAX_INDEX,
_vkIndexes,
_individual_vks_inputs,
_subproofs_limbs,
vk
);
// #endif
}

function verifyExitProof(
bytes32 _rootHash,
uint32 _accountId,
address _owner,
uint16 _tokenId,
uint128 _amount,
uint256[] calldata _proof
) external view returns (bool) {
bytes32 commitment =
sha256(abi.encodePacked(uint256(_rootHash) & INPUT_MASK, _accountId, _owner, _tokenId, _amount));

uint256[] memory inputs = new uint256[](1);
inputs[0] = uint256(commitment) & INPUT_MASK;
ProofOld memory proof = deserialize_proof_old(inputs, _proof);
VerificationKeyOld memory vk = getVkExit();
require(vk.num_inputs == inputs.length);
return verify_old(proof, vk);
}
}
22 changes: 4 additions & 18 deletions contracts/contracts/ZkSync.sol
Original file line number Diff line number Diff line change
Expand Up @@ -468,13 +468,12 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
}

bool success =
verifier.verifyAggregatedProof(
verifier.verifyAggregatedBlockProof(
_proof.recursiveInput,
_proof.proof,
_proof.vkIndexes,
_proof.commitments,
_proof.subproofsLimbs,
true
_proof.subproofsLimbs
);
require(success, "p"); // Aggregated proof verification fail

Expand Down Expand Up @@ -541,28 +540,15 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
uint32 _accountId,
uint16 _tokenId,
uint128 _amount,
ProofInput memory _proof
uint256[] memory _proof
) external nonReentrant {
bytes22 packedBalanceKey = packAddressAndTokenId(_owner, _tokenId);
require(exodusMode, "s"); // must be in exodus mode
require(!performedExodus[_accountId][_tokenId], "t"); // already exited
require(storedBlockHashes[totalBlocksExecuted] == hashStoredBlockInfo(_storedBlockInfo), "u"); // incorrect sotred block info

uint256 commitment =
uint256(sha256(abi.encodePacked(_storedBlockInfo.stateHash, _accountId, _owner, _tokenId, _amount)));
require(_proof.commitments.length == 1, "v");
commitment = commitment & INPUT_MASK;
require(_proof.commitments[0] == commitment, "w");

bool proofCorrect =
verifier.verifyAggregatedProof(
_proof.recursiveInput,
_proof.proof,
_proof.vkIndexes,
_proof.commitments,
_proof.subproofsLimbs,
false
);
verifier.verifyExitProof(_storedBlockInfo.stateHash, _accountId, _owner, _tokenId, _amount, _proof);
require(proofCorrect, "x");

increaseBalanceToWithdraw(packedBalanceKey, _amount);
Expand Down
2 changes: 0 additions & 2 deletions core/bin/key_generator/src/sample_proofs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//!
use std::fs::File;
use zksync_circuit::witness::WitnessBuilder;
use zksync_config::AvailableBlockSizesConfig;
use zksync_crypto::circuit::CircuitAccountTree;
Expand All @@ -9,7 +8,6 @@ use zksync_crypto::proof::{PrecomputedSampleProofs, SingleProof};
use zksync_prover_utils::aggregated_proofs::{gen_aggregate_proof, prepare_proof_data};
use zksync_prover_utils::fs_utils::get_precomputed_proofs_path;
use zksync_prover_utils::{PlonkVerificationKey, SetupForStepByStepProver};
use zksync_types::tokens::TokenLike::Address;
use zksync_types::{Account, BlockNumber};

fn generate_zksync_circuit_proofs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ contract KeysWithPlonkVerifier is VerifierWithDeserialize {

uint256 constant VK_TREE_ROOT = {{vk_tree_root}};
uint8 constant VK_MAX_INDEX = {{vk_max_index}};
uint256 constant VK_EXIT_TREE_ROOT = {{vk_tree_root_exit}};

function getVkAggregated(uint32 _proofs) internal pure returns (VerificationKey memory vk) {
{{~#each sizes ~}}
Expand Down Expand Up @@ -100,3 +99,79 @@ contract KeysWithPlonkVerifier is VerifierWithDeserialize {
{{/each}}

}

// Hardcoded constants to avoid accessing store
contract KeysWithPlonkVerifierOld is VerifierWithDeserializeOld {

{{#each single_keys}}
function {{key_getter_name}}() internal pure returns(VerificationKeyOld memory vk) {
vk.domain_size = {{domain_size}};
vk.num_inputs = {{num_inputs}};
vk.omega = PairingsBn254.new_fr({{omega}});
vk.selector_commitments[0] = PairingsBn254.new_g1(
{{selector_commitment_0_0}},
{{selector_commitment_0_1}}
);
vk.selector_commitments[1] = PairingsBn254.new_g1(
{{selector_commitment_1_0}},
{{selector_commitment_1_1}}
);
vk.selector_commitments[2] = PairingsBn254.new_g1(
{{selector_commitment_2_0}},
{{selector_commitment_2_1}}
);
vk.selector_commitments[3] = PairingsBn254.new_g1(
{{selector_commitment_3_0}},
{{selector_commitment_3_1}}
);
vk.selector_commitments[4] = PairingsBn254.new_g1(
{{selector_commitment_4_0}},
{{selector_commitment_4_1}}
);
vk.selector_commitments[5] = PairingsBn254.new_g1(
{{selector_commitment_5_0}},
{{selector_commitment_5_1}}
);

// we only have access to value of the d(x) witness polynomial on the next
// trace step, so we only need one element here and deal with it in other places
// by having this in mind
vk.next_step_selector_commitments[0] = PairingsBn254.new_g1(
{{next_step_selector_commitment_0_0}},
{{next_step_selector_commitment_0_1}}
);

vk.permutation_commitments[0] = PairingsBn254.new_g1(
{{permutation_commitment_0_0}},
{{permutation_commitment_0_1}}
);
vk.permutation_commitments[1] = PairingsBn254.new_g1(
{{permutation_commitment_1_0}},
{{permutation_commitment_1_1}}
);
vk.permutation_commitments[2] = PairingsBn254.new_g1(
{{permutation_commitment_2_0}},
{{permutation_commitment_2_1}}
);
vk.permutation_commitments[3] = PairingsBn254.new_g1(
{{permutation_commitment_3_0}},
{{permutation_commitment_3_1}}
);

vk.permutation_non_residues[0] = PairingsBn254.new_fr(
{{permutation_non_residue_0}}
);
vk.permutation_non_residues[1] = PairingsBn254.new_fr(
{{permutation_non_residue_1}}
);
vk.permutation_non_residues[2] = PairingsBn254.new_fr(
{{permutation_non_residue_2}}
);

vk.g2_x = PairingsBn254.new_g2(
[{{g2_x_x_c1}}, {{g2_x_x_c0}}],
[{{g2_x_y_c1}}, {{g2_x_y_c0}}]
);
}
{{/each}}
}
14 changes: 7 additions & 7 deletions core/bin/key_generator/src/verifier_contract_generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use handlebars::to_json;
use handlebars::Handlebars;

use crate::verifier_contract_generator::render_vk::{
get_exit_vk_tree_root_hash, get_vk_tree_root_hash, rendered_key,
get_vk_tree_root_hash, rendered_key, rendered_key_single_proof,
};
use zksync_config::AvailableBlockSizesConfig;
use zksync_prover_utils::fs_utils::{
get_recursive_verification_key_path, get_verifier_contract_key_path,
get_exodus_verification_key_path, get_recursive_verification_key_path,
get_verifier_contract_key_path,
};
use zksync_utils::parse_env;

Expand All @@ -29,11 +30,6 @@ pub(crate) fn create_verifier_contract(config: AvailableBlockSizesConfig) {
to_json(get_vk_tree_root_hash(&config.blocks_chunks)),
);

template_params.insert(
"vk_tree_root_exit".to_string(),
to_json(get_exit_vk_tree_root_hash()),
);

template_params.insert(
"vk_max_index".to_string(),
to_json(config.blocks_chunks.len() - 1),
Expand All @@ -56,6 +52,10 @@ pub(crate) fn create_verifier_contract(config: AvailableBlockSizesConfig) {
.collect::<Vec<_>>();
template_params.insert("keys".to_string(), to_json(templates_for_key_getters));

let exodus_key_path = get_exodus_verification_key_path();
let exodus_key = rendered_key_single_proof("getVkExit", exodus_key_path);
template_params.insert("single_keys".to_string(), to_json(vec![exodus_key]));

let res = Handlebars::new()
.render_template(template, &template_params)
.expect("failed to render Verifiers.sol template");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ use std::path::Path;

use handlebars::to_json;

use zksync_crypto::bellman::plonk::better_better_cs::setup::VerificationKey;
use zksync_crypto::bellman::plonk::domains::Domain;
use zksync_crypto::bellman::plonk::{
better_better_cs::setup::VerificationKey,
better_cs::{
cs::PlonkCsWidth4WithNextStepParams, keys::VerificationKey as SingleVerificationKey,
},
domains::Domain,
};
use zksync_crypto::ff::{PrimeField, PrimeFieldRepr};
use zksync_crypto::pairing::{CurveAffine, Engine};
use zksync_crypto::recursive_aggregation_circuit::circuit::RecursiveAggregationCircuitBn256;
Expand Down Expand Up @@ -84,12 +89,67 @@ pub(crate) fn rendered_key(
to_json(map)
}

pub fn get_vk_tree_root_hash(block_chunks: &[usize]) -> String {
render_scalar_to_hex(&PlonkVerificationKey::get_vk_tree_root_hash(block_chunks))
pub(crate) fn rendered_key_single_proof(
key_getter_name: &str,
verification_key: impl AsRef<Path>,
) -> serde_json::Value {
let vk = SingleVerificationKey::<NodeEngine, PlonkCsWidth4WithNextStepParams>::read(
File::open(verification_key).expect("Failed to open verfifcation key file"),
)
.expect("Failed to read verification key");
let mut map = HashMap::new();
let domain_size = vk.n.next_power_of_two().to_string();
map.insert("domain_size".to_owned(), to_json(domain_size));
let num_inputs = vk.num_inputs.to_string();
map.insert("num_inputs".to_owned(), to_json(num_inputs));
let domain = Domain::<Fr>::new_for_size(vk.n.next_power_of_two() as u64).unwrap();
let omega = domain.generator;
map.insert("omega".to_owned(), to_json(render_scalar_to_hex(&omega)));
for (i, c) in vk.selector_commitments.iter().enumerate() {
let rendered = render_g1_affine_to_hex::<NodeEngine>(&c);

for (j, rendered) in rendered.iter().enumerate() {
map.insert(
format!("selector_commitment_{}_{}", i, j),
to_json(rendered),
);
}
}
for (i, c) in vk.next_step_selector_commitments.iter().enumerate() {
let rendered = render_g1_affine_to_hex::<NodeEngine>(&c);

for (j, rendered) in rendered.iter().enumerate() {
map.insert(
format!("next_step_selector_commitment_{}_{}", i, j),
to_json(rendered),
);
}
}
for (i, c) in vk.permutation_commitments.iter().enumerate() {
let rendered = render_g1_affine_to_hex::<NodeEngine>(&c);
for (j, rendered) in rendered.iter().enumerate() {
map.insert(
format!("permutation_commitment_{}_{}", i, j),
to_json(rendered),
);
}
}
for (i, c) in vk.non_residues.into_iter().enumerate() {
let rendered = render_scalar_to_hex(&c);
map.insert(format!("permutation_non_residue_{}", i), to_json(&rendered));
}
let rendered = render_g2_affine_to_hex(&vk.g2_elements[1]);
map.insert("g2_x_x_c0".to_owned(), to_json(&rendered[0]));
map.insert("g2_x_x_c1".to_owned(), to_json(&rendered[1]));
map.insert("g2_x_y_c0".to_owned(), to_json(&rendered[2]));
map.insert("g2_x_y_c1".to_owned(), to_json(&rendered[3]));

map.insert("key_getter_name".to_string(), to_json(key_getter_name));
to_json(map)
}

pub fn get_exit_vk_tree_root_hash() -> String {
render_scalar_to_hex(&PlonkVerificationKey::get_vk_tree_root_hash_exit_proof())
pub fn get_vk_tree_root_hash(block_chunks: &[usize]) -> String {
render_scalar_to_hex(&PlonkVerificationKey::get_vk_tree_root_hash(block_chunks))
}

fn render_scalar_to_hex<F: PrimeField>(el: &F) -> String {
Expand Down
2 changes: 1 addition & 1 deletion core/bin/zksync_eth_sender/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const RATE_LIMIT_HTTP_CODE: &str = "429";
/// constants for gas limit calculation
const BASE_COMMIT_BLOCKS_TX_COST: usize = 36_000;
const BASE_EXECUTE_BLOCKS_TX_COST: usize = 55_000;
const BASE_PROOF_BLOCKS_TX_COST: usize = 500_000;
const BASE_PROOF_BLOCKS_TX_COST: usize = 1_000_000;

/// `TxCheckMode` enum determines the policy on the obtaining the tx status.
/// The latest sent transaction can be pending (we're still waiting for it),
Expand Down
Loading

0 comments on commit aef22e1

Please sign in to comment.