Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some additional test to verify ecrecovery with TxId and coin witness #495

Merged
merged 1 commit into from
Jun 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions fuel-vm/src/tests/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,141 @@ fn ecrecover() {

assert!(success);
}

#[test]
fn ecrecover_tx_id() {
let rng = &mut StdRng::seed_from_u64(2322u64);

let mut client = MemoryClient::default();

let gas_price = 0;
let gas_limit = 1_000_000;
let maturity = Default::default();
let height = Default::default();
let params = ConsensusParameters::default();
let gas_costs = GasCosts::default();

let secret = SecretKey::random(rng);
let public = secret.public_key();

#[rustfmt::skip]
let script = vec![
// 0x21 is a address of the singer of the witness
op::gtf_args(0x20, 0x00, GTFArgs::ScriptData),
op::move_(0x21, 0x20),
// 0x22 is a witness - signature
op::gtf_args(0x22, 0x00, GTFArgs::WitnessData),
// TxId is stored in the first 32 bytes of the memory
// Store it into register 0x23
op::movi(0x23, 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: registers are zeroed already on initialization

// Allocate space for the recovered public key
// 0x10 contains the size of the public key = PublicKey::LEN
op::movi(0x10, PublicKey::LEN as Immediate18),
op::aloc(0x10),
op::move_(0x11, RegId::HP),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: assigning to a register is not needed, RegId::HP could be used directly in place of 0x11 after this.

// Recover public key into `0x11` from `0x22` signature and TxId `0x23`
op::ecr(0x11, 0x22, 0x23),
// Compare address `0x21` from script data with with recovered `0x11`
// for length `0x10` = PublicKey::LEN
op::meq(0x12, 0x21, 0x11, 0x10),
op::ret(0x12),
].into_iter().collect();

let script_data = public.as_ref().to_vec();

let mut tx = TransactionBuilder::script(script, script_data)
.gas_price(gas_price)
.gas_limit(gas_limit)
.maturity(maturity)
.with_params(params)
.add_random_fee_input()
.finalize();

tx.sign_inputs(&secret, &params.chain_id);
let tx = tx.into_checked(height, &params, &gas_costs).unwrap();

let receipts = client.transact(tx);
let success = receipts
.iter()
.any(|r| matches!(r, Receipt::Return{ val, .. } if *val == 1));

assert!(success);
}

#[test]
fn ecrecover_tx_id_predicate() {
use crate::checked_transaction::EstimatePredicates;
use rand::Rng;
let rng = &mut StdRng::seed_from_u64(1234u64);

let gas_price = 0;
let gas_limit = 1_000_000;
let maturity = Default::default();
let params = ConsensusParameters::default();
let gas_costs = GasCosts::default();

let secret = SecretKey::random(rng);
let public = secret.public_key();

#[rustfmt::skip]
let predicate = vec![
// 0x21 is a address of the singer of the witness
op::gtf_args(0x20, 0x00, GTFArgs::ScriptData),
op::move_(0x21, 0x20),
// 0x22 is a witness - signature
op::gtf_args(0x22, 0x00, GTFArgs::WitnessData),
// TxId is stored in the first 32 bytes of the memory
// Store it into register 0x23
op::movi(0x23, 0),
// Allocate space for the recovered public key
// 0x10 contains the size of the public key = PublicKey::LEN
op::movi(0x10, PublicKey::LEN as Immediate18),
op::aloc(0x10),
op::move_(0x11, RegId::HP),
// Recover public key into `0x11` from `0x22` signature and TxId `0x23`
op::ecr(0x11, 0x22, 0x23),
// Compare address `0x21` from script data with with recovered `0x11`
// for length `0x10` = PublicKey::LEN
op::meq(0x12, 0x21, 0x11, 0x10),
op::ret(0x12),
].into_iter().collect();

let script_data = public.as_ref().to_vec();

let input = Input::coin_predicate(
rng.gen(),
Input::predicate_owner(&predicate, &params.chain_id),
1000,
rng.gen(),
Default::default(),
rng.gen(),
0,
predicate,
vec![],
);

let mut tx = TransactionBuilder::script(vec![], script_data)
.gas_price(gas_price)
.gas_limit(gas_limit)
.maturity(maturity)
.with_params(params)
.add_input(input)
.add_unsigned_coin_input(
secret,
rng.gen(),
rng.gen(),
rng.gen(),
Default::default(),
Default::default(),
)
.finalize();

tx.estimate_predicates(&params, &gas_costs)
.expect("Should estimate predicate successfully");
tx.into_checked(maturity, &params, &gas_costs)
.expect("Should check predicate successfully");
}

#[test]
fn ecrecover_error() {
let rng = &mut StdRng::seed_from_u64(2322u64);
Expand Down