Skip to content

Commit

Permalink
added e2e test when feature is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
alinush committed Mar 1, 2024
1 parent a3361e6 commit f50cb63
Show file tree
Hide file tree
Showing 17 changed files with 212 additions and 119 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions aptos-move/aptos-vm/src/keyless_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,14 @@ pub(crate) fn validate_authenticators(
training_wheels_pk.as_ref().unwrap(),
&public_inputs_hash,
)
.map_err(|_| {
.map_err(|_|
invalid_signature!("Could not verify training wheels signature")
})?;
)?;
}

proof
.verify_proof(public_inputs_hash, pvk)
.map_err(|_| invalid_signature!("Proof verification failed"))?;
.map_err(|_| invalid_signature!("Proof verification failed") )?;
},
JWK::Unsupported(_) => return Err(invalid_signature!("JWK is not supported")),
},
Expand Down Expand Up @@ -208,5 +208,6 @@ pub(crate) fn validate_authenticators(
},
}
}

Ok(())
}
1 change: 0 additions & 1 deletion aptos-move/e2e-move-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ aptos-package-builder = { workspace = true }
aptos-types = { workspace = true }
aptos-vm = { workspace = true, features = ["testing"] }
aptos-vm-genesis = { workspace = true }
ark-ff = { workspace = true }
bcs = { workspace = true }
claims = { workspace = true }
hex = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 0d06e418a86d5a07e5ac65d22e86d78a819989e1e0815db4750efcc12dc9d905 # shrinks to block_split = Whole
cc c5ad38cf3be8dea3f90d1504b070a030228a03829c63964d2855e8946d17ffe6 # shrinks to block_split = Whole
2 changes: 2 additions & 0 deletions aptos-move/e2e-move-tests/src/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ impl MoveHarness {
}

/// Reads the resource data `T`.
/// WARNING: Does not work with resource groups (because set_resource does not work?).
pub fn read_resource<T: DeserializeOwned>(
&self,
addr: &AccountAddress,
Expand Down Expand Up @@ -714,6 +715,7 @@ impl MoveHarness {
}

/// Write the resource data `T`.
/// WARNING: Does not work with resource groups.
pub fn set_resource<T: Serialize>(
&mut self,
addr: AccountAddress,
Expand Down
122 changes: 86 additions & 36 deletions aptos-move/e2e-move-tests/src/tests/keyless_feature_gating.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
// Copyright © Aptos Foundation

use crate::MoveHarness;
use crate::{assert_success, build_package, tests::common, MoveHarness};
use aptos_cached_packages::aptos_stdlib;
use aptos_crypto::SigningKey;
use aptos_language_e2e_tests::account::{Account, TransactionBuilder};
use aptos_crypto::{hash::CryptoHash, SigningKey};
use aptos_language_e2e_tests::account::{Account, AccountPublicKey, TransactionBuilder};
use aptos_types::{
keyless::{test_utils::get_sample_groth16_sig_and_pk, KeylessPublicKey, KeylessSignature},
keyless::{
test_utils::{
get_sample_esk, get_sample_groth16_sig_and_pk, get_sample_iss, get_sample_jwk,
},
Configuration, KeylessPublicKey, KeylessSignature, ZkpOrOpenIdSig,
},
on_chain_config::FeatureFlag,
transaction::{
authenticator::{AnyPublicKey, AuthenticationKey},
SignedTransaction, TransactionStatus,
authenticator::{AnyPublicKey, AuthenticationKey, EphemeralSignature},
Script, SignedTransaction, Transaction, TransactionStatus,
},
};
use aptos_types::keyless::test_utils::{get_sample_esk, get_sample_jwk};
use aptos_types::keyless::{Configuration, get_public_inputs_hash, Groth16ZkpAndStatement, ZkpOrOpenIdSig};
use aptos_types::transaction::authenticator::EphemeralSignature;
use move_core_types::{
account_address::AccountAddress, vm_status::StatusCode::FEATURE_UNDER_GATING,
account_address::AccountAddress, transaction_argument::TransactionArgument,
vm_status::StatusCode::FEATURE_UNDER_GATING,
};
use ark_ff::{BigInteger, PrimeField};

// TODO(keyless): Initialize keyless_account.move

#[test]
fn test_keyless_feature_gating() {
fn test_keyless_feature_is_disabled() {
let mut h = MoveHarness::new_with_features(vec![], vec![FeatureFlag::KEYLESS_ACCOUNTS]);

let (sig, pk) = get_sample_groth16_sig_and_pk();
let bob = h.new_account_at(AccountAddress::from_hex_literal("0xb0b").unwrap());

let transaction = get_keyless_signed_txn(&mut h, sig, pk, bob);
let transaction = get_keyless_groth16_txn(&mut h, sig, pk, bob);

let output = h.run_raw(transaction);
match output.status() {
Expand All @@ -42,45 +42,53 @@ fn test_keyless_feature_gating() {
}
}

#[test]
fn test_keyless_feature_is_enabled() {
let mut h = MoveHarness::new_with_features(vec![FeatureFlag::KEYLESS_ACCOUNTS], vec![]);

let (sig, pk) = get_sample_groth16_sig_and_pk();
let bob = h.new_account_at(AccountAddress::from_hex_literal("0xb0b").unwrap());

// initialize JWK
run_setup_script(&mut h);

let transaction = get_keyless_groth16_txn(&mut h, sig, pk, bob);

let output = h.run_raw(transaction);
assert_success!(output.status().clone());
}

/// Creates and funds a new account at `pk` and sends coins to `recipient`.
fn get_keyless_signed_txn(
fn get_keyless_groth16_txn(
h: &mut MoveHarness,
mut sig: KeylessSignature,
pk: KeylessPublicKey,
recipient: Account,
) -> SignedTransaction {
let apk = AnyPublicKey::keyless(pk.clone());
let addr = AuthenticationKey::any_key(apk.clone()).account_address();
let account = h.store_and_fund_account(&Account::new_from_addr(addr), 100000000, 0);
let account = h.store_and_fund_account(
&Account::new_from_addr(addr, AccountPublicKey::Keyless(pk.clone())),
100000000,
0,
);

println!("Actual address: {}", addr.to_hex());
println!("Account address: {}", account.address().to_hex());

let payload = aptos_stdlib::aptos_coin_transfer(*recipient.address(), 1);
//println!("Payload: {:?}", payload);
let raw_txn = TransactionBuilder::new(account.clone())
.payload(payload)
.sequence_number(h.sequence_number(account.address()))
.max_gas_amount(1_000_000)
.gas_unit_price(1)
.sign() // dummy signature, which we discard below
.into_raw_transaction();
.raw();

println!("RawTxn sender: {:?}", raw_txn.sender());

let esk = get_sample_esk();
sig.ephemeral_signature = EphemeralSignature::ed25519(esk.sign(&raw_txn).unwrap());
let jwk = get_sample_jwk();
// TODO: might need new_for_devnet() here; forget how the MoveHarness is initialized
let config = Configuration::new_for_testing();

let public_inputs_hash: Option<[u8; 32]> = if let ZkpOrOpenIdSig::Groth16Zkp(_) = &sig.sig {
// This will only calculate the hash if it's needed, avoiding unnecessary computation.
Some(
get_public_inputs_hash(&sig, &pk, &jwk, &config)
.unwrap()
.into_bigint()
.to_bytes_le()
.try_into()
.expect("expected 32-byte public inputs hash"),
)
} else {
None
};

// Compute the training wheels signature if not present
match &mut sig.sig {
Expand All @@ -92,5 +100,47 @@ fn get_keyless_signed_txn(
}

let transaction = SignedTransaction::new_keyless(raw_txn, pk, sig);
println!(
"Submitted TXN hash: {}",
Transaction::UserTransaction(transaction.clone()).hash()
);
transaction
}

fn run_setup_script(h: &mut MoveHarness) {
let core_resources = h.new_account_at(AccountAddress::from_hex_literal("0xA550C18").unwrap());

let package = build_package(
common::test_dir_path("keyless_setup.data/pack"),
aptos_framework::BuildOptions::default(),
)
.expect("building package must succeed");

let txn = h.create_publish_built_package(&core_resources, &package, |_| {});
assert_success!(h.run(txn));

let script = package.extract_script_code()[0].clone();

let iss = get_sample_iss();
let jwk = get_sample_jwk();
let config = Configuration::new_for_testing();

let txn = TransactionBuilder::new(core_resources.clone())
.script(Script::new(script, vec![], vec![
TransactionArgument::U8Vector(iss.into_bytes()),
TransactionArgument::U8Vector(jwk.kid.into_bytes()),
TransactionArgument::U8Vector(jwk.alg.into_bytes()),
TransactionArgument::U8Vector(jwk.e.into_bytes()),
TransactionArgument::U8Vector(jwk.n.into_bytes()),
TransactionArgument::U64(config.max_exp_horizon_secs),
]))
.sequence_number(h.sequence_number(&core_resources.address()))
.max_gas_amount(1_000_000)
.gas_unit_price(1)
.sign();

// NOTE: We cannot write the Configuration and Groth16Verification key via MoveHarness::set_resource
// because it does not (yet) work with resource groups.

assert_success!(h.run(txn));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = 'InsertJwk'
version = "0.0.0"

[dependencies]
AptosFramework = { local = "../../../../../framework/aptos-framework" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
script {
use aptos_framework::jwks;
use aptos_framework::aptos_governance;
use aptos_framework::keyless_account;
use std::string::utf8;

fun main(core_resources: &signer, iss: vector<u8>, kid: vector<u8>, alg: vector<u8>, e: vector<u8>, n: vector<u8>, max_exp_horizon_secs: u64) {
let fx = aptos_governance::get_signer_testnet_only(core_resources, @aptos_framework);
let jwk = jwks::new_rsa_jwk(
utf8(kid),
utf8(alg),
utf8(e),
utf8(n)
);

let patches = vector[
jwks::new_patch_remove_all(),
jwks::new_patch_upsert_jwk(iss, jwk),
];
jwks::set_patches(&fx, patches);

keyless_account::update_max_exp_horizon(&fx, max_exp_horizon_secs);
}
}
2 changes: 1 addition & 1 deletion aptos-move/e2e-move-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod generate_upgrade_script;
mod governance_updates;
mod infinite_loop;
mod init_module;
mod keyless_feature_gating;
mod lazy_natives;
mod max_loop_depth;
mod memory_quota;
Expand Down Expand Up @@ -49,4 +50,3 @@ mod type_too_large;
mod vector_numeric_address;
mod vm;
mod vote;
mod keyless_feature_gating;
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn offer_rotation_capability_v2(
aptos_stdlib::account_offer_rotation_capability(
rotation_proof_signed.to_bytes().to_vec(),
0,
offerer_account.pubkey.to_bytes().to_vec(),
offerer_account.pubkey.to_bytes(),
*delegate_account.address(),
)
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn offer_signer_capability_v2() {
aptos_stdlib::account_offer_signer_capability(
signature.to_bytes().to_vec(),
0,
account_alice.pubkey.to_bytes().to_vec(),
account_alice.pubkey.to_bytes(),
*account_bob.address(),
)
));
Expand Down
25 changes: 11 additions & 14 deletions aptos-move/e2e-move-tests/src/tests/rotate_auth_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn rotate_auth_key_ed25519_to_ed25519() {
*account1.address(),
0,
account2.privkey.clone(),
account2.pubkey.clone(),
account2.pubkey.to_bytes(),
);

// verify that we can still get to account1's originating address
Expand All @@ -60,7 +60,7 @@ fn rotate_auth_key_ed25519_to_multi_ed25519() {
*account1.address(),
0,
private_key,
public_key,
public_key.to_bytes(),
);

// verify that we can still get to account1's originating address
Expand All @@ -82,10 +82,10 @@ fn rotate_auth_key_twice() {
*account1.address(),
0,
account2.privkey.clone(),
account2.pubkey.clone(),
account2.pubkey.to_bytes(),
);
// rotate account1's keypair to account2
account1.rotate_key(account2.privkey, account2.pubkey);
account1.rotate_key(account2.privkey, account2.pubkey.as_ed25519().unwrap());
// verify that we can still get to account1's originating address
verify_originating_address(&mut harness, account1.auth_key(), *account1.address(), 1);

Expand All @@ -98,9 +98,9 @@ fn rotate_auth_key_twice() {
*account1.address(),
1,
account3.privkey.clone(),
account3.pubkey.clone(),
account3.pubkey.to_bytes(),
);
account1.rotate_key(account3.privkey, account3.pubkey);
account1.rotate_key(account3.privkey, account3.pubkey.as_ed25519().unwrap());
verify_originating_address(&mut harness, account1.auth_key(), *account1.address(), 2);
}

Expand Down Expand Up @@ -174,18 +174,15 @@ fn run_rotate_auth_key_with_rotation_capability(
)
}

pub fn assert_successful_key_rotation_transaction<
S: SigningKey + ValidCryptoMaterial,
V: ValidCryptoMaterial,
>(
pub fn assert_successful_key_rotation_transaction<S: SigningKey + ValidCryptoMaterial>(
from_scheme: u8,
to_scheme: u8,
harness: &mut MoveHarness,
current_account: Account,
originator: AccountAddress,
sequence_number: u64,
new_private_key: S,
new_public_key: V,
new_public_key_bytes: Vec<u8>,
) {
// Construct a proof challenge struct that proves that
// the user intends to rotate their auth key.
Expand All @@ -196,7 +193,7 @@ pub fn assert_successful_key_rotation_transaction<
sequence_number,
originator,
current_auth_key: AccountAddress::from_bytes(current_account.auth_key()).unwrap(),
new_public_key: new_public_key.to_bytes().to_vec(),
new_public_key: new_public_key_bytes.clone(),
};

let rotation_msg = bcs::to_bytes(&rotation_proof).unwrap();
Expand All @@ -211,9 +208,9 @@ pub fn assert_successful_key_rotation_transaction<
&current_account,
aptos_stdlib::account_rotate_authentication_key(
from_scheme,
current_account.pubkey.to_bytes().to_vec(),
current_account.pubkey.to_bytes(),
to_scheme,
new_public_key.to_bytes().to_vec(),
new_public_key_bytes,
signature_by_curr_privkey.to_bytes().to_vec(),
signature_by_new_privkey.to_bytes().to_vec(),
)
Expand Down
Loading

0 comments on commit f50cb63

Please sign in to comment.