Skip to content

Conversation

@roeierez
Copy link
Member

@roeierez roeierez commented Dec 17, 2025

Refactors the signing architecture by introducing a unified BreezSigner trait and specialized adapter implementations:

  • BreezSignerImpl: Core signer implementation
  • SparkSigner: Adapter for spark-wallet operations
  • NostrSigner: Adapter for Nostr event signing
  • RTSyncSigner: Adapter for real-time sync signing/encryption

@roeierez roeierez marked this pull request as ready for review December 22, 2025 12:18
Copy link
Collaborator

@danielgranhao danielgranhao left a comment

Choose a reason for hiding this comment

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

Looking good! Just a few comments

Copy link
Collaborator

@JssDWt JssDWt left a comment

Choose a reason for hiding this comment

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

Looking good.

// This forces users to sync from scratch to the sync server.
// Also delete the sync_initial_complete flag to force re-populating
// all payment metadata for outgoing sync using the new key.
name: "Clear sync tables for BreezSigner backward compatibility",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This needs a migration in the web storage as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

Comment on lines 132 to 146
async fn sign_hash_schnorr(
&self,
hash: &[u8],
path: &DerivationPath,
) -> Result<secp256k1::schnorr::Signature, SdkError> {
let derived = self
.key_set
.identity_master_key
.derive_priv(&self.secp, path)
.map_err(|e| SdkError::Generic(e.to_string()))?;
let message =
Message::from_digest_slice(hash).map_err(|e| SdkError::Generic(e.to_string()))?;
let keypair = derived.private_key.keypair(&self.secp);
Ok(self.secp.sign_schnorr(&message, &keypair))
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should these be forwarded to the Spark signer as well, where possible? The sign_schnorr implementation here uses auxiliary randomness, while the spark signer implementation doesn't. Perhaps the Spark signer can sign based on a derivation path as well? Not sure what's the best approach here, since the signer will be split anyway. Perhaps the best thing is to not forward anything to the Spark signer at all.

Copy link
Member Author

Choose a reason for hiding this comment

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

added a flag to whether use randomness or not. For spark used without randomness for nostr with (as it was before this change).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure we need/should be using schnorr signing without aux rand. I checked, and it seems I introduced it, but probably was a mistake? If we see that all itests are green with rand, I would go ahead and and always use it.

As far as I can see, the JS SDK always uses aux rand.

Comment on lines 29 to 31
let identity_path = "m"
.parse()
.map_err(|e: bitcoin::bip32::Error| SignerError::Generic(e.to_string()))?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This loses the KeySet functionality. It seems wrong to me that this SparkSigner passes the request to the BreezSigner, which passes it to DefaultSigner. Perhaps BreezSigner should have a SparkSigner, and the SparkSigner should have a DefaultSigner? Or maybe DefaultSigner shouldn't be used at all?

Copy link
Member Author

Choose a reason for hiding this comment

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

@JssDWt I am not sure I follow here, let me explain the rational I use here:

  1. BreezSigner is the signer breez sdk needs. It currently uses under the hood an instance of spark DefaultSigner
  2. All other signers (rtsync, nostr, spark) depends on BreeSigner as adapters. Since BreezSigner eventually might be passed to the sdk by the user we must have SparkSigner depends on it.

The"under the hood" spark DefaultSigner that is used by BreezSigner is initialized with the right keyset so I don't see how we loose the keyset functionality.
LMK if I am missing anything here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see, the dependency structure makes sense then.

An issue here is the identity key has a different derivation path for different keysets. Passing derivation path m is not backward compatible with the currently used keysets.

Copy link
Member Author

Choose a reason for hiding this comment

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

As discussed offline, this is backward compatible as we do use the right keyset in the underline spark signer.

Comment on lines +258 to +262
"DELETE FROM sync_outgoing;
DELETE FROM sync_incoming;
DELETE FROM sync_state;
UPDATE sync_revision SET revision = 0;
DELETE FROM settings WHERE key = 'sync_initial_complete';",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Confirming: We delete all remote data. So sync depends on data being present locally to resync with the sync_initial_complete flag. Someone that doesn't have local persistent storage between sessions will lose all metadata. Any pending outgoing changes may be missed/lost. Is that intended?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unless I understand it wrong, only restore will will not sync in any metadata. Any upgrade to an existing instance will sync out everything (including pending changes as all local data is re-synced).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, agreed.

So if someone doesn't have persistent local storage, they lose their payment metadata.

(cherry picked from commit 2339157d7669dd451437fec07e1edbfc0833bbda)
(cherry picked from commit 26723fe6f72be6ca7b9c0d0ab097bfe592434c29)
@roeierez roeierez requested a review from JssDWt January 5, 2026 20:44
@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

Copy link
Collaborator

@danielgranhao danielgranhao left a comment

Choose a reason for hiding this comment

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

LGTM

@roeierez roeierez merged commit 0701ac9 into main Jan 7, 2026
17 checks passed
@roeierez roeierez deleted the breez-signer branch January 7, 2026 13:29
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.

4 participants