Skip to content

Add signer trait to the simplicity-core#58

Closed
ikripaka wants to merge 1 commit intomainfrom
feature/signer
Closed

Add signer trait to the simplicity-core#58
ikripaka wants to merge 1 commit intomainfrom
feature/signer

Conversation

@ikripaka
Copy link
Copy Markdown
Collaborator

  • Signer trait would help in future create easy to use finalization of transactions

@ikripaka ikripaka self-assigned this Jan 21, 2026
@ikripaka ikripaka requested a review from KyrylR as a code owner January 21, 2026 12:22
@ikripaka ikripaka changed the title Add signer trait to the simplicity-core Add signer trait to the simplicity-contracts Jan 21, 2026
@ikripaka ikripaka changed the title Add signer trait to the simplicity-contracts Add signer trait to the simplicity-core Jan 22, 2026

/// Get the dummy keypair used for fee estimation.
/// This keypair is deterministic and used only to produce valid transaction structures.
#[allow(unused)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is weird

Copy link
Copy Markdown
Collaborator Author

@ikripaka ikripaka Jan 22, 2026

Choose a reason for hiding this comment

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

clippy warns about it
DummySigner can be used in some tests

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why we are adding private functionality to the crate which intention to provide tools for external crates?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ok, in some case DummySigner can be deleted , because can be unused by others

Comment on lines +47 to +91
/// Returns a closure that signs a transaction with dummy signatures.
///
/// This is used for fee estimation - the transaction needs valid witness data
/// to calculate accurate weight/fees, but the actual signatures don't need
/// to be cryptographically valid for spending (they just need to be the right size).
#[allow(clippy::type_complexity, unused)]
pub(crate) fn get_signer_closure() -> impl SignerTrait {
|network: SimplicityNetwork, tx: Transaction, utxos: &[TxOut]| {
let keypair = Self::get_dummy_keypair();
let x_only_public_key = keypair.x_only_public_key().0;
let p2pk_program = get_p2pk_program(&x_only_public_key)?;
let cmr = p2pk_program.commit().cmr();

let dummy_address =
create_p2tr_address(cmr, &x_only_public_key, network.address_params());
let dummy_script_pubkey = dummy_address.script_pubkey();

let dummy_utxos: Vec<TxOut> = utxos
.iter()
.map(|utxo: &TxOut| TxOut {
script_pubkey: dummy_script_pubkey.clone(),
..utxo.clone()
})
.collect();

let mut signed_tx = tx;

for i in 0..signed_tx.input.len() {
let signature =
create_p2pk_signature(&signed_tx, &dummy_utxos, &keypair, i, network)?;

signed_tx = finalize_p2pk_transaction(
signed_tx,
&dummy_utxos,
&x_only_public_key,
&signature,
i,
network,
TrackerLogLevel::None,
)?;
}

Ok(signed_tx)
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The function name and what it actually does is different

Copy link
Copy Markdown
Collaborator Author

@ikripaka ikripaka Jan 22, 2026

Choose a reason for hiding this comment

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

That is the DummySigner - the idea was to create type, which would be responsible for signing, which doesn't require valid Keypair for signing.
Due to internal checks of ScriptPubkey we have to manually change owner of utxo.
Yeah, it changes owner of utxo on draft keypair and signs as p2pk utxo.

Comment on lines +10 to +29
pub trait SignerTrait:
Fn(SimplicityNetwork, Transaction, &[TxOut]) -> Result<Transaction, ProgramError> + Clone
{
}

impl<T> SignerTrait for T where
T: Fn(SimplicityNetwork, Transaction, &[TxOut]) -> Result<Transaction, ProgramError> + Clone
{
}

#[allow(dead_code)]
pub trait SignerOnceTrait:
FnOnce(SimplicityNetwork, Transaction, &[TxOut]) -> Result<Transaction, ProgramError>
{
}

impl<T> SignerOnceTrait for T where
T: FnOnce(SimplicityNetwork, Transaction, &[TxOut]) -> Result<Transaction, ProgramError>
{
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Explain the idea pls

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

For standard finalization, if we need to calculate fees from scratch we must call valid signing function twice.
However if we provide our own values the transaction would be signed only once.

Therefore this traits can be used to bound the invocation of sign functions.
We can use SignerTrait to invoke another function that is bounded by SignerOnceTrait.

  • since SignerTrait is an Fn, it implements FnOnce by default. This allows us to invoke a function that performs the signing operation only once.
  • SignerOnceTrait can also be used in external code by users who want to restrict specific traits to sign function that can only be called once.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

So the the idea lies in restricting even inner functions to FnOnce even if we receive Fn

let dummy_utxos: Vec<TxOut> = utxos
.iter()
.map(|utxo: &TxOut| TxOut {
script_pubkey: dummy_script_pubkey.clone(),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This looks wrong

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ok, exactly in this case I wanted to define DummySigner as draft one, which can be used in any case
by using it wihout script_pubkey is impossible, code would fail

we can redefine it with trait which would give Keypair type to function and sign only with p2pk(lets say P2pkSigner), but in this way we mabe lose flexibilty of creating signature to any utxo
I mean some utxos has to be signed in another way than p2pk

(I've looked through all signing functions and by now we only require p2pk)

So, maybe it makes sense to define DummySigner as P2pkSigner, which would by giving

Copy link
Copy Markdown
Collaborator Author

@ikripaka ikripaka Jan 23, 2026

Choose a reason for hiding this comment

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

ok, maybe it makes sense to define signer like this?

pub trait P2PKSigner {
    fn x_only_public_key() -> XOnlyPublicKey;
    fn sign_p2pk_utxo(&self, network: SimplicityNetwork, tx: Transaction, utxos: &[TxOut], input_index: usize) -> Result<Transaction, ProgramError>;
}

pub struct SimpleSigner {}

impl P2PKSigner for SimpleSigner {
    fn sign_p2pk_utxo(&self, network: SimplicityNetwork, tx: Transaction, utxos: &[TxOut], input_index: usize) -> Result<Transaction, ProgramError>{
        keypair.sign_schnorr(sighash_all)
    }
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

we would leave Keypair storage on the Wallet or any user implementation and in the same way we'd feed signed bytes into our backend where it is needed

@@ -0,0 +1,92 @@
use crate::{
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It is unclear how it should be used

Copy link
Copy Markdown
Collaborator Author

@ikripaka ikripaka Jan 23, 2026

Choose a reason for hiding this comment

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

It should be used together with simplicityhl-core errors and functions

functions is related only to DummySigner, but trait can be used with ProgramError

@KyrylR
Copy link
Copy Markdown
Collaborator

KyrylR commented Jan 29, 2026

I would like to reiterate on the approach, closing the PR for the time being

@KyrylR KyrylR closed this Jan 29, 2026
@KyrylR KyrylR deleted the feature/signer branch February 12, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants