Skip to content

Commit

Permalink
Add sighash tests (kaspanet#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
someone235 authored Dec 6, 2022
1 parent 3e1fa9b commit 34cadf6
Show file tree
Hide file tree
Showing 2 changed files with 328 additions and 12 deletions.
338 changes: 327 additions & 11 deletions consensus/core/src/hashing/sighash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ pub fn calc_schnorr_signature_hash(

#[cfg(test)]
mod tests {
use std::str::FromStr;
use std::{str::FromStr, vec};

use smallvec::SmallVec;

use crate::{
hashing::sighash_type::SIG_HASH_ALL,
hashing::sighash_type::{SIG_HASH_ALL, SIG_HASH_ANY_ONE_CAN_PAY, SIG_HASH_NONE, SIG_HASH_SINGLE},
subnets::SubnetworkId,
tx::{Transaction, TransactionId, TransactionInput, UtxoEntry},
};
Expand All @@ -196,7 +196,7 @@ mod tests {
faster_hex::hex_decode("20fcef4c106cf11135bbd70f02a726a92162d2fb8b22f0469126f800862ad884e8ac".as_bytes(), &mut bytes).unwrap();
let script_pub_key_2 = SmallVec::from_vec(bytes.to_vec());

let tx = Transaction::new(
let native_tx = Transaction::new(
0,
vec![
TransactionInput {
Expand All @@ -223,13 +223,41 @@ mod tests {
TransactionOutput { value: 300, script_public_key: ScriptPublicKey::new(0, script_pub_key_1.clone()) },
],
1615462089000,
SubnetworkId::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
SUBNETWORK_ID_NATIVE,
0,
vec![],
);

let populated_tx = PopulatedTransaction::new(
&tx,
let native_populated_tx = PopulatedTransaction::new(
&native_tx,
vec![
UtxoEntry {
amount: 100,
script_public_key: ScriptPublicKey::new(0, script_pub_key_1.clone()),
block_daa_score: 0,
is_coinbase: false,
},
UtxoEntry {
amount: 200,
script_public_key: ScriptPublicKey::new(0, script_pub_key_2.clone()),
block_daa_score: 0,
is_coinbase: false,
},
UtxoEntry {
amount: 300,
script_public_key: ScriptPublicKey::new(0, script_pub_key_2.clone()),
block_daa_score: 0,
is_coinbase: false,
},
],
);

let mut subnetwork_tx = native_tx.clone();
subnetwork_tx.subnetwork_id = SubnetworkId::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
subnetwork_tx.gas = 250;
subnetwork_tx.payload = vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
let subnetwork_populated_tx = PopulatedTransaction::new(
&subnetwork_tx,
vec![
UtxoEntry {
amount: 100,
Expand All @@ -252,10 +280,298 @@ mod tests {
],
);

let mut reused_values = SigHashReusedValues::new();
assert_eq!(
calc_schnorr_signature_hash(&populated_tx, 0, SIG_HASH_ALL, &mut reused_values).to_string(),
"b363613fe99c8bb1d3712656ec8dfaea621ee6a9a95d851aec5bb59363b03f5e"
);
enum ModifyAction {
NoAction,
Output(usize),
Input(usize),
AmountSpent(usize),
PrevScriptPublicKey(usize),
Sequence(usize),
Payload,
Gas,
SubnetworkId,
}

struct TestVector<'a> {
name: &'static str,
populated_tx: &'a PopulatedTransaction<'a>,
hash_type: SigHashType,
input_index: usize,
action: ModifyAction,
expected_hash: &'static str,
}

const SIG_HASH_ALL_ANYONE_CAN_PAY: SigHashType = SigHashType(SIG_HASH_ALL.0 | SIG_HASH_ANY_ONE_CAN_PAY.0);
const SIG_HASH_NONE_ANYONE_CAN_PAY: SigHashType = SigHashType(SIG_HASH_NONE.0 | SIG_HASH_ANY_ONE_CAN_PAY.0);
const SIG_HASH_SINGLE_ANYONE_CAN_PAY: SigHashType = SigHashType(SIG_HASH_SINGLE.0 | SIG_HASH_ANY_ONE_CAN_PAY.0);

let tests = [
// SIG_HASH_ALL
TestVector {
name: "native-all-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "03b7ac6927b2b67100734c3cc313ff8c2e8b3ce3e746d46dd660b706a916b1f5",
},
TestVector {
name: "native-all-0-modify-input-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::Input(1),
expected_hash: "a9f563d86c0ef19ec2e4f483901d202e90150580b6123c3d492e26e7965f488c", // should change the hash
},
TestVector {
name: "native-all-0-modify-output-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::Output(1),
expected_hash: "aad2b61bd2405dfcf7294fc2be85f325694f02dda22d0af30381cb50d8295e0a", // should change the hash
},
TestVector {
name: "native-all-0-modify-sequence-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::Sequence(1),
expected_hash: "0818bd0a3703638d4f01014c92cf866a8903cab36df2fa2506dc0d06b94295e8", // should change the hash
},
TestVector {
name: "native-all-anyonecanpay-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2", // should change the hash
},
TestVector {
name: "native-all-anyonecanpay-0-modify-input-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::Input(0),
expected_hash: "d09cb639f335ee69ac71f2ad43fd9e59052d38a7d0638de4cf989346588a7c38", // should change the hash
},
TestVector {
name: "native-all-anyonecanpay-0-modify-input-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::Input(1),
expected_hash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2", // shouldn't change the hash
},
TestVector {
name: "native-all-anyonecanpay-0-modify-sequence",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_ALL_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::Sequence(1),
expected_hash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2", // shouldn't change the hash
},
// SIG_HASH_NONE
TestVector {
name: "native-none-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba", // should change the hash
},
TestVector {
name: "native-none-0-modify-output-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE,
input_index: 0,
action: ModifyAction::Output(1),
expected_hash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba", // shouldn't change the hash
},
TestVector {
name: "native-none-0-modify-output-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE,
input_index: 0,
action: ModifyAction::Output(1),
expected_hash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba", // should change the hash
},
TestVector {
name: "native-none-0-modify-sequence-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE,
input_index: 0,
action: ModifyAction::Sequence(0),
expected_hash: "d9efdd5edaa0d3fd0133ee3ab731d8c20e0a1b9f3c0581601ae2075db1109268", // shouldn't change the hash
},
TestVector {
name: "native-none-0-modify-sequence-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE,
input_index: 0,
action: ModifyAction::Sequence(1),
expected_hash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba", // should change the hash
},
TestVector {
name: "native-none-anyonecanpay-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "06aa9f4239491e07bb2b6bda6b0657b921aeae51e193d2c5bf9e81439cfeafa0", // should change the hash
},
TestVector {
name: "native-none-anyonecanpay-0-modify-amount-spent",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::AmountSpent(0),
expected_hash: "f07f45f3634d3ea8c0f2cb676f56e20993edf9be07a83bf0dfdb3debcf1441bf", // should change the hash
},
TestVector {
name: "native-none-anyonecanpay-0-modify-script-public-key",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_NONE_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::PrevScriptPublicKey(0),
expected_hash: "20a525c54dc33b2a61201f05233c086dbe8e06e9515775181ed96550b4f2d714", // should change the hash
},
// SIG_HASH_SINGLE
TestVector {
name: "native-single-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005", // should change the hash
},
TestVector {
name: "native-single-0-modify-output-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 0,
action: ModifyAction::Output(1),
expected_hash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005", // should change the hash
},
TestVector {
name: "native-single-0-modify-sequence-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 0,
action: ModifyAction::Sequence(0),
expected_hash: "83796d22879718eee1165d4aace667bb6778075dab579c32c57be945f466a451", // should change the hash
},
TestVector {
name: "native-single-0-modify-sequence-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 0,
action: ModifyAction::Sequence(1),
expected_hash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005", // shouldn't change the hash
},
TestVector {
name: "native-single-2-no-corresponding-output",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 2,
action: ModifyAction::NoAction,
expected_hash: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0", // should change the hash
},
TestVector {
name: "native-single-2-no-corresponding-output-modify-output-1",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE,
input_index: 2,
action: ModifyAction::Output(1),
expected_hash: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0", // shouldn't change the hash
},
TestVector {
name: "native-single-anyonecanpay-0",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE_ANYONE_CAN_PAY,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "43b20aba775050cf9ba8d5e48fc7ed2dc6c071d23f30382aea58b7c59cfb8ed7", // should change the hash
},
TestVector {
name: "native-single-anyonecanpay-2-no-corresponding-output",
populated_tx: &native_populated_tx,
hash_type: SIG_HASH_SINGLE_ANYONE_CAN_PAY,
input_index: 2,
action: ModifyAction::NoAction,
expected_hash: "846689131fb08b77f83af1d3901076732ef09d3f8fdff945be89aa4300562e5f", // should change the hash
},
// subnetwork transaction
TestVector {
name: "subnetwork-all-0",
populated_tx: &subnetwork_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::NoAction,
expected_hash: "b2f421c933eb7e1a91f1d9e1efa3f120fe419326c0dbac487752189522550e0c", // should change the hash
},
TestVector {
name: "subnetwork-all-modify-payload",
populated_tx: &subnetwork_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::Payload,
expected_hash: "12ab63b9aea3d58db339245a9b6e9cb6075b2253615ce0fb18104d28de4435a1", // should change the hash
},
TestVector {
name: "subnetwork-all-modify-gas",
populated_tx: &subnetwork_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::Gas,
expected_hash: "2501edfc0068d591160c4bd98646c6e6892cdc051182a8be3ccd6d67f104fd17", // should change the hash
},
TestVector {
name: "subnetwork-all-subnetwork-id",
populated_tx: &subnetwork_populated_tx,
hash_type: SIG_HASH_ALL,
input_index: 0,
action: ModifyAction::SubnetworkId,
expected_hash: "a5d1230ede0dfcfd522e04123a7bcd721462fed1d3a87352031a4f6e3c4389b6", // should change the hash
},
];

for test in tests {
let mut tx = test.populated_tx.tx.clone();
let mut entries = test.populated_tx.entries.clone();
match test.action {
ModifyAction::NoAction => {}
ModifyAction::Output(i) => {
tx.outputs[i].value = 100;
}
ModifyAction::Input(i) => {
tx.inputs[i].previous_outpoint.index = 2;
}
ModifyAction::AmountSpent(i) => {
entries[i].amount = 666;
}
ModifyAction::PrevScriptPublicKey(i) => {
let mut script_vec = entries[i].script_public_key.script().to_vec();
script_vec.append(&mut vec![1, 2, 3]);
entries[i].script_public_key = ScriptPublicKey::new(entries[i].script_public_key.version(), script_vec.into());
}
ModifyAction::Sequence(i) => {
tx.inputs[i].sequence = 12345;
}
ModifyAction::Payload => tx.payload = vec![6, 6, 6, 4, 2, 0, 1, 3, 3, 7],
ModifyAction::Gas => tx.gas = 1234,
ModifyAction::SubnetworkId => {
tx.subnetwork_id = SubnetworkId::from_bytes([6, 6, 6, 4, 2, 0, 1, 3, 3, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
}
}
let populated_tx = PopulatedTransaction::new(&tx, entries);
let mut reused_values = SigHashReusedValues::new();
assert_eq!(
calc_schnorr_signature_hash(&populated_tx, test.input_index, test.hash_type, &mut reused_values).to_string(),
test.expected_hash,
"test {} failed",
test.name
);
}
}
}
2 changes: 1 addition & 1 deletion consensus/core/src/hashing/sighash_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ALLOWED_SIG_HASH_TYPES_VALUES: [u8; 6] = [
];

#[derive(Copy, Clone)]
pub struct SigHashType(u8);
pub struct SigHashType(pub(crate) u8);

impl SigHashType {
pub fn is_sighash_all(self) -> bool {
Expand Down

0 comments on commit 34cadf6

Please sign in to comment.