Skip to content

Commit

Permalink
feat: add signer-sig check to delegate-stack-extend
Browse files Browse the repository at this point in the history
  • Loading branch information
hstove committed Jan 24, 2024
1 parent d5302da commit 89d8a7f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 79 deletions.
2 changes: 2 additions & 0 deletions stackslib/src/chainstate/stacks/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,7 @@ pub mod test {
pox_addr: PoxAddress,
signer_key: StacksPublicKey,
extend_count: u128,
signature: Vec<u8>,
) -> StacksTransaction {
let payload: TransactionPayload = TransactionPayload::new_contract_call(
boot_code_test_addr(),
Expand All @@ -1874,6 +1875,7 @@ pub mod test {
Value::Principal(stacker.clone()),
Value::Tuple(pox_addr.as_clarity_tuple().unwrap()),
Value::UInt(extend_count),
Value::buff_from(signature).unwrap(),
Value::buff_from(signer_key.to_bytes_compressed()).unwrap(),
],
)
Expand Down
33 changes: 20 additions & 13 deletions stackslib/src/chainstate/stacks/boot/pox-4.clar
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@
(err ERR_STACKING_INSUFFICIENT_FUNDS))

;; Validate ownership of the given signer key
(try! (verify-signing-key-signature tx-sender signer-key signer-sig))
(try! (verify-signer-key-sig tx-sender signer-key signer-sig))

;; ensure that stacking can be performed
(try! (can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))
Expand Down Expand Up @@ -678,7 +678,10 @@

(ok true)))

;; Generate a message hash following the SIP018 standard.
;; Generate a message hash for validating a signer key.
;; The message hash follows SIP018 for signing structured data. The structured data
;; is the tuple `{ stacker, reward-cycle }`. The domain is
;; `{ name: "pox-4-signer", version: "1.0.0", chain-id: chain-id }`.
(define-read-only (get-signer-key-message-hash (signer-key (buff 33)) (stacker principal))
(let
(
Expand All @@ -695,20 +698,20 @@
)

;; Verify a signature from the signing key for this specific stacker.
;; The message hash is the sha256 of the consensus hash of the tuple
;; `{ stacker, reward-cycle }`. Note that `reward-cycle` corresponds to the
;; _current_ reward cycle, not the reward cycle at which the delegation will start.
;; The public key is recovered from the signature and compared to the pubkey hash
;; of the delegator.
(define-read-only (verify-signing-key-signature (stacker principal)
(signing-key (buff 33))
;; See `get-signer-key-message-hash` for details on the message hash.
;;
;; Note that `reward-cycle` corresponds to the _current_ reward cycle,
;; not the reward cycle at which the delegation will start.
;; The public key is recovered from the signature and compared to `signer-key`.
(define-read-only (verify-signer-key-sig (stacker principal)
(signer-key (buff 33))
(signer-sig (buff 65)))
(let
(
(msg-hash (get-signer-key-message-hash signing-key stacker))
(msg-hash (get-signer-key-message-hash signer-key stacker))
(pubkey (unwrap! (secp256k1-recover? msg-hash signer-sig) ERR_DELEGATION_INVALID_SIGNATURE)) ;; TODO
)
(asserts! (is-eq pubkey signing-key) ERR_DELEGATION_INVALID_SIGNATURE)
(asserts! (is-eq pubkey signer-key) ERR_DELEGATION_INVALID_SIGNATURE)
(ok true)
)
)
Expand Down Expand Up @@ -873,7 +876,7 @@
(err ERR_STACKING_PERMISSION_DENIED))

;; Verify signature from delegate that allows this sender for this cycle
(try! (verify-signing-key-signature stacker signer-key signer-sig))
(try! (verify-signer-key-sig stacker signer-key signer-sig))

;; stacker must have delegated to the caller
(let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED))))
Expand Down Expand Up @@ -1054,7 +1057,7 @@
(err ERR_STACKING_IS_DELEGATED))

;; Verify signature from delegate that allows this sender for this cycle
(try! (verify-signing-key-signature tx-sender signer-key signer-sig))
(try! (verify-signer-key-sig tx-sender signer-key signer-sig))

;; ensure the signer key can be used
(try! (insert-signer-key signer-key))
Expand Down Expand Up @@ -1208,6 +1211,7 @@
(stacker principal)
(pox-addr { version: (buff 1), hashbytes: (buff 32) })
(extend-count uint)
(signer-sig (buff 65))
(signer-key (buff 33)))
(let ((stacker-info (stx-account stacker))
;; to extend, there must already be an entry in the stacking-state
Expand Down Expand Up @@ -1242,6 +1246,9 @@
(asserts! (is-eq (len (get reward-set-indexes stacker-state)) u0)
(err ERR_STACKING_NOT_DELEGATED))

;; Validate that the owner of the signing key is allowing this stacker
(try! (verify-signer-key-sig stacker signer-key signer-sig))

;; stacker must be delegated to tx-sender
(asserts! (is-eq (unwrap! (get delegated-to stacker-state)
(err ERR_STACKING_NOT_DELEGATED))
Expand Down
117 changes: 51 additions & 66 deletions stackslib/src/chainstate/stacks/boot/pox_4_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use crate::burnchains::{Burnchain, PoxConstants};
use crate::chainstate::burn::db::sortdb::SortitionDB;
use crate::chainstate::burn::operations::*;
use crate::chainstate::burn::{BlockSnapshot, ConsensusHash};
use crate::chainstate::coordinator::tests::pox_addr_from;
use crate::chainstate::stacks::address::{PoxAddress, PoxAddressType20, PoxAddressType32};
use crate::chainstate::stacks::boot::pox_2_tests::{
check_pox_print_event, generate_pox_clarity_value, get_reward_set_entries_at,
Expand Down Expand Up @@ -1406,13 +1407,12 @@ fn generate_signer_key_sig_msg_hash(
structured_data_message_hash(data_tuple, domain_tuple)
}

fn validate_signer_key_sig(
fn verify_signer_key_sig(
signature: &Vec<u8>,
signing_key: &Secp256k1PublicKey,
stacker: &PrincipalData,
peer: &mut TestPeer,
burnchain: &Burnchain,
coinbase_nonce: &mut usize,
latest_block: &StacksBlockId,
) -> Value {
let result: Value = with_sortdb(peer, |ref mut chainstate, ref mut sortdb| {
Expand All @@ -1428,7 +1428,7 @@ fn validate_signer_key_sig(
LimitedCostTracker::new_free(),
|env| {
let program = format!(
"(verify-signing-key-signature '{} 0x{} 0x{})",
"(verify-signer-key-sig '{} 0x{} 0x{})",
stacker.to_string(),
signing_key.to_hex(),
to_hex(&signature),
Expand All @@ -1444,7 +1444,7 @@ fn validate_signer_key_sig(
}

#[test]
fn validate_signer_key_sigs() {
fn verify_signer_key_signatures() {
let (epochs, pox_constants) = make_test_epochs_pox();

let mut burnchain = Burnchain::default_unittest(
Expand Down Expand Up @@ -1491,18 +1491,17 @@ fn validate_signer_key_sigs() {

let expected_error = Value::error(Value::Int(35)).unwrap();

// Test 1: invalid block-height used in signature
// Test 1: invalid reward cycle used in signature

let last_reward_cycle = reward_cycle - 1;
let signature = make_signer_key_signature(&alice_principal, &bob, last_reward_cycle);

let result = validate_signer_key_sig(
let result = verify_signer_key_sig(
&signature,
&bob_public_key,
&alice_principal,
&mut peer,
&burnchain,
&mut coinbase_nonce,
&latest_block,
);
assert_eq!(result, expected_error);
Expand All @@ -1511,13 +1510,12 @@ fn validate_signer_key_sigs() {

let signature = make_signer_key_signature(&bob_principal, &bob, reward_cycle);

let result = validate_signer_key_sig(
let result = verify_signer_key_sig(
&signature,
&bob_public_key,
&alice_principal, // different stacker
&mut peer,
&burnchain,
&mut coinbase_nonce,
&latest_block,
);

Expand All @@ -1527,34 +1525,27 @@ fn validate_signer_key_sigs() {

let signature = make_signer_key_signature(&alice_principal, &alice, reward_cycle);

let result = validate_signer_key_sig(
let result = verify_signer_key_sig(
&signature,
&bob_public_key, // different key
&alice_principal,
&mut peer,
&burnchain,
&mut coinbase_nonce,
&latest_block,
);

assert_eq!(result, expected_error);

// Test 4: using a valid signature

// println!("Reward cycle: {}", reward_cycle);
// let reward_cycle = get_current_reward_cycle(&peer, &burnchain);
// println!("Reward cycle: {}", reward_cycle);
// // println!("")

let signature = make_signer_key_signature(&alice_principal, &bob, reward_cycle);

let result = validate_signer_key_sig(
let result = verify_signer_key_sig(
&signature,
&bob_public_key,
&alice_principal,
&mut peer,
&burnchain,
&mut coinbase_nonce,
&latest_block,
);

Expand Down Expand Up @@ -1656,22 +1647,20 @@ fn stack_stx_signer_key() {
// (start-burn-ht uint)
// (lock-period uint)
// (signer-key (buff 33)))
let pox_addr = make_pox_addr(
AddressHashMode::SerializeP2WSH,
key_to_stacks_addr(stacker_key).bytes,
);
let txs = vec![make_pox_4_contract_call(
stacker_key,
// let pox_addr = make_pox_addr(
// AddressHashMode::SerializeP2WSH,
// key_to_stacks_addr(stacker_key).bytes,
// );
let pox_addr = pox_addr_from(signer_key);
let txs = vec![make_pox_4_lockup(
&stacker_key,
stacker_nonce,
"stack-stx",
vec![
Value::UInt(min_ustx),
pox_addr,
Value::UInt(block_height as u128),
Value::UInt(2),
Value::buff_from(signature.clone()).unwrap(),
signer_key_val.clone(),
],
min_ustx,
pox_addr_from(signer_key),
2_u128,
signer_public_key,
block_height,
signature,
)];

let latest_block = peer.tenure_with_txs(&txs, &mut coinbase_nonce);
Expand Down Expand Up @@ -1718,31 +1707,25 @@ fn stack_stx_signer_key_no_reuse() {

let signature_val = Value::buff_from(first_signature.clone()).unwrap();
let txs = vec![
make_pox_4_contract_call(
first_stacker_key,
make_pox_4_lockup(
&first_stacker_key,
first_stacker_nonce,
"stack-stx",
vec![
Value::UInt(min_ustx),
pox_addr.clone(),
Value::UInt(block_height as u128),
Value::UInt(2),
Value::buff_from(first_signature.clone()).unwrap(),
signer_key_val.clone(),
],
min_ustx,
pox_addr_from(first_stacker_key),
lock_period,
signer_public_key,
block_height,
first_signature,
),
make_pox_4_contract_call(
second_stacker_key,
make_pox_4_lockup(
&second_stacker_key,
second_stacker_nonce,
"stack-stx",
vec![
Value::UInt(min_ustx),
pox_addr.clone(),
Value::UInt(block_height as u128),
Value::UInt(2),
Value::buff_from(second_signature.clone()).unwrap(),
signer_key_val.clone(),
],
min_ustx,
pox_addr_from(second_stacker_key),
lock_period,
signer_public_key,
block_height,
second_signature,
),
];

Expand Down Expand Up @@ -1792,18 +1775,15 @@ fn stack_extend_signer_key() {

let signature = make_signer_key_signature(&stacker, &signer_key, reward_cycle);

let txs = vec![make_pox_4_contract_call(
stacker_key,
let txs = vec![make_pox_4_lockup(
&stacker_key,
stacker_nonce,
"stack-stx",
vec![
Value::UInt(min_ustx),
pox_addr.clone(),
Value::UInt(block_height as u128),
Value::UInt(2),
Value::buff_from(signature.clone()).unwrap(),
signer_key_val.clone(),
],
min_ustx,
pox_addr_from(&stacker_key),
lock_period,
signer_public_key,
block_height,
signature,
)];

stacker_nonce += 1;
Expand Down Expand Up @@ -1944,6 +1924,7 @@ fn delegate_stack_stx_extend_signer_key() {

let mut alice_nonce = 0;
let alice_stacker_key = &keys[0];
let alice_principal = PrincipalData::from(key_to_stacks_addr(alice_stacker_key));
let bob_nonce = 0;
let bob_delegate_private_key = &keys[1];
let bob_delegate_principal = PrincipalData::from(key_to_stacks_addr(bob_delegate_private_key));
Expand Down Expand Up @@ -2005,13 +1986,17 @@ fn delegate_stack_stx_extend_signer_key() {

alice_nonce += 1;

let signature =
make_signer_key_signature(&alice_principal, &bob_new_signer_private_key, reward_cycle);

let delegate_stack_extend = make_pox_4_delegate_stack_extend(
bob_delegate_private_key,
alice_nonce,
alice_principal.clone(),
pox_addr.clone(),
bob_new_signer_public_key.clone(),
1,
signature,
);

// Next tx arr calls a delegate_stack_extend pox_4 helper found in mod.rs
Expand Down

0 comments on commit 89d8a7f

Please sign in to comment.