Repository: bisq-network/bisq2
Pull request #3516: Handle redacted PartialSignatures
Author: login: HenrikJannsen
Created: 2025-05-22T14:29:22Z | Merged: 2025-05-23T11:13:09Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced support for redacted partial signatures in MuSig trade messages, enhancing privacy by sharing only necessary signature components between peers.
  - Added handling and exchange of swap transaction input partial signatures in relevant trade message flows.

- **Bug Fixes**
  - Improved serialization to prevent backend errors when handling empty signature fields.

- **Refactor**
  - Updated message formats and internal handling to use redacted partial signatures instead of full signatures where appropriate, streamlining the signature exchange process.

- **Documentation**
  - Removed outdated or redundant inline comments for improved code clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/common/src/main/java/bisq/common/util/OptionalUtils.java b/common/src/main/java/bisq/common/util/OptionalUtils.java
index a2c7e379c9..8313a13fb4 100644
--- a/common/src/main/java/bisq/common/util/OptionalUtils.java
+++ b/common/src/main/java/bisq/common/util/OptionalUtils.java
@@ -1,9 +1,8 @@
 package bisq.common.util;
 
+import java.util.Arrays;
 import java.util.Optional;
 
-import static bisq.common.util.StringUtils.toNullIfEmpty;
-
 public class OptionalUtils {
 
     public static Optional<String> toOptional(String value) {
@@ -13,4 +12,10 @@ public static Optional<String> toOptional(String value) {
     public static Optional<String> normalize(Optional<String> optional) {
         return Optional.ofNullable(optional).orElse(Optional.empty());
     }
+
+    // Using default equals method for an Optional<byte[]> would use comparison by reference not by value.
+    public static boolean optionalByteArrayEquals(Optional<byte[]> a, Optional<byte[]> b) {
+        return a.isPresent() == b.isPresent() &&
+                (a.isEmpty() || Arrays.equals(a.get(), b.get()));
+    }
 }
diff --git a/trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java b/trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java
index 2990b19556..b3aee1aa43 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java
@@ -29,6 +29,7 @@
 import bisq.trade.mu_sig.messages.network.vo.NonceShares;
 import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
 import bisq.trade.mu_sig.messages.network.vo.PubKeyShares;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import bisq.trade.mu_sig.messages.network.vo.SwapTxSignature;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
@@ -46,6 +47,7 @@ public final class MuSigTradeParty extends TradeParty {
     private Optional<NonceShares> peersNonceShares = Optional.empty();
     private Optional<PartialSignaturesMessage> myPartialSignaturesMessage = Optional.empty();
     private Optional<PartialSignatures> peersPartialSignatures = Optional.empty();
+    private Optional<RedactedPartialSignatures> peersRedactedPartialSignatures = Optional.empty();
     private Optional<DepositPsbt> myDepositPsbt = Optional.empty();
     private Optional<SwapTxSignatureResponse> mySwapTxSignatureResponse = Optional.empty();
     private Optional<SwapTxSignature> peersSwapTxSignature = Optional.empty();
@@ -63,6 +65,7 @@ public MuSigTradeParty(NetworkId networkId,
                            Optional<NonceShares> peersNonceShares,
                            Optional<PartialSignaturesMessage> myPartialSignaturesMessage,
                            Optional<PartialSignatures> peersPartialSignatures,
+                           Optional<RedactedPartialSignatures> peersRedactedPartialSignatures,
                            Optional<DepositPsbt> myDepositPsbt,
                            Optional<SwapTxSignatureResponse> mySwapTxSignatureResponse,
                            Optional<SwapTxSignature> peersSwapTxSignature,
@@ -76,6 +79,7 @@ public MuSigTradeParty(NetworkId networkId,
         this.peersNonceShares = peersNonceShares;
         this.myPartialSignaturesMessage = myPartialSignaturesMessage;
         this.peersPartialSignatures = peersPartialSignatures;
+        this.peersRedactedPartialSignatures = peersRedactedPartialSignatures;
         this.myDepositPsbt = myDepositPsbt;
         this.mySwapTxSignatureResponse = mySwapTxSignatureResponse;
         this.peersSwapTxSignature = peersSwapTxSignature;
@@ -92,6 +96,7 @@ public bisq.trade.protobuf.TradeParty.Builder getBuilder(boolean serializeForHas
         peersNonceShares.ifPresent(e -> builder.setPeersNonceShares(e.toProto(serializeForHash)));
         myPartialSignaturesMessage.ifPresent(e -> builder.setMyPartialSignaturesMessage(e.toProto(serializeForHash)));
         peersPartialSignatures.ifPresent(e -> builder.setPeersPartialSignatures(e.toProto(serializeForHash)));
+        peersRedactedPartialSignatures.ifPresent(e -> builder.setPeersRedactedPartialSignatures(e.toProto(serializeForHash)));
         myDepositPsbt.ifPresent(e -> builder.setMyDepositPsbt(e.toProto(serializeForHash)));
         mySwapTxSignatureResponse.ifPresent(e -> builder.setMySwapTxSignatureResponse(e.toProto(serializeForHash)));
         peersSwapTxSignature.ifPresent(e -> builder.setPeersSwapTxSignature(e.toProto(serializeForHash)));
@@ -122,6 +127,9 @@ public static MuSigTradeParty fromProto(bisq.trade.protobuf.TradeParty proto) {
                 muSigTradePartyProto.hasPeersPartialSignatures()
                         ? Optional.of(PartialSignatures.fromProto(muSigTradePartyProto.getPeersPartialSignatures()))
                         : Optional.empty(),
+                muSigTradePartyProto.hasPeersRedactedPartialSignatures()
+                        ? Optional.of(RedactedPartialSignatures.fromProto(muSigTradePartyProto.getPeersRedactedPartialSignatures()))
+                        : Optional.empty(),
                 muSigTradePartyProto.hasMyDepositPsbt()
                         ? Optional.of(DepositPsbt.fromProto(muSigTradePartyProto.getMyDepositPsbt()))
                         : Optional.empty(),
@@ -164,6 +172,10 @@ public void setPeersPartialSignatures(PartialSignatures peersPartialSignatures)
         this.peersPartialSignatures = Optional.of(peersPartialSignatures);
     }
 
+    public void setPeersRedactedPartialSignatures(RedactedPartialSignatures peersRedactedPartialSignatures) {
+        this.peersRedactedPartialSignatures = Optional.of(peersRedactedPartialSignatures);
+    }
+
     public void setMyDepositPsbt(DepositPsbt myDepositPsbt) {
         this.myDepositPsbt = Optional.of(myDepositPsbt);
     }
diff --git a/trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java b/trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java
index 90d58bb033..d91f1e38df 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java
@@ -22,6 +22,7 @@
 import bisq.trade.mu_sig.MuSigTrade;
 import bisq.trade.mu_sig.handler.MuSigTradeEventHandlerAsMessageSender;
 import bisq.trade.mu_sig.messages.network.MuSigPaymentInitiatedMessage_E;
+import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
 
 public final class MuSigPaymentInitiatedEventHandler extends MuSigTradeEventHandlerAsMessageSender<MuSigTrade, MuSigPaymentInitiatedEvent> {
     public MuSigPaymentInitiatedEventHandler(ServiceProvider serviceProvider, MuSigTrade model) {
@@ -39,11 +40,14 @@ protected void commit() {
 
     @Override
     protected void sendMessage() {
+        PartialSignatures partialSignatures = PartialSignatures.from(trade.getMyself().getMyPartialSignaturesMessage().orElseThrow());
+        byte[] swapTxInputPartialSignature = partialSignatures.getSwapTxInputPartialSignature();
         send(new MuSigPaymentInitiatedMessage_E(StringUtils.createUid(),
                 trade.getId(),
                 trade.getProtocolVersion(),
                 trade.getMyIdentity().getNetworkId(),
-                trade.getPeer().getNetworkId()));
+                trade.getPeer().getNetworkId(),
+                swapTxInputPartialSignature));
     }
 
     @Override
diff --git a/trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java b/trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java
index af2076ec52..52465c174d 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java
@@ -41,12 +41,10 @@ public MuSigPaymentReceiptConfirmedEventHandler(ServiceProvider serviceProvider,
     @Override
     public void process(MuSigPaymentReceiptConfirmedEvent event) {
         MuSigTradeParty peer = trade.getTaker();
-        // We got that from an earlier message
         PartialSignatures peersPartialSignatures = peer.getPeersPartialSignatures().orElseThrow();
 
         mySwapTxSignatureResponse = SwapTxSignatureResponse.fromProto(musigBlockingStub.signSwapTx(SwapTxSignatureRequest.newBuilder()
                 .setTradeId(trade.getId())
-                // NOW send the redacted buyer's swapTxInputPartialSignature:
                 .setSwapTxInputPeersPartialSignature(ByteString.copyFrom(peersPartialSignatures.getSwapTxInputPartialSignature()))
                 .build()));
 
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java b/trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
index ae0cd7e334..9f2e717d78 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
@@ -18,11 +18,14 @@
 package bisq.trade.mu_sig.messages.grpc;
 
 import bisq.common.proto.Proto;
+import bisq.common.util.OptionalUtils;
 import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import com.google.protobuf.ByteString;
 import lombok.Getter;
 
 import java.util.Arrays;
+import java.util.Optional;
 
 @Getter
 public final class PartialSignaturesMessage implements Proto {
@@ -31,19 +34,28 @@ public static PartialSignaturesMessage from(PartialSignatures peersPartialSignat
                 peersPartialSignatures.getPeersWarningTxBuyerInputPartialSignature(),
                 peersPartialSignatures.getPeersWarningTxSellerInputPartialSignature(),
                 peersPartialSignatures.getPeersRedirectTxInputPartialSignature(),
-                peersPartialSignatures.getSwapTxInputPartialSignature()
+                Optional.of(peersPartialSignatures.getSwapTxInputPartialSignature())
+        );
+    }
+
+    public static PartialSignaturesMessage from(RedactedPartialSignatures peersPartialSignatures) {
+        return new PartialSignaturesMessage(
+                peersPartialSignatures.getPeersWarningTxBuyerInputPartialSignature(),
+                peersPartialSignatures.getPeersWarningTxSellerInputPartialSignature(),
+                peersPartialSignatures.getPeersRedirectTxInputPartialSignature(),
+                Optional.empty()
         );
     }
 
     private final byte[] peersWarningTxBuyerInputPartialSignature;
     private final byte[] peersWarningTxSellerInputPartialSignature;
     private final byte[] peersRedirectTxInputPartialSignature;
-    private final byte[] swapTxInputPartialSignature;
+    private final Optional<byte[]> swapTxInputPartialSignature;
 
     public PartialSignaturesMessage(byte[] peersWarningTxBuyerInputPartialSignature,
                                     byte[] peersWarningTxSellerInputPartialSignature,
                                     byte[] peersRedirectTxInputPartialSignature,
-                                    byte[] swapTxInputPartialSignature) {
+                                    Optional<byte[]> swapTxInputPartialSignature) {
         this.peersWarningTxBuyerInputPartialSignature = peersWarningTxBuyerInputPartialSignature;
         this.peersWarningTxSellerInputPartialSignature = peersWarningTxSellerInputPartialSignature;
         this.peersRedirectTxInputPartialSignature = peersRedirectTxInputPartialSignature;
@@ -52,11 +64,12 @@ public PartialSignaturesMessage(byte[] peersWarningTxBuyerInputPartialSignature,
 
     @Override
     public bisq.trade.protobuf.PartialSignaturesMessage.Builder getBuilder(boolean serializeForHash) {
-        return bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
+        bisq.trade.protobuf.PartialSignaturesMessage.Builder builder = bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
                 .setPeersWarningTxBuyerInputPartialSignature(ByteString.copyFrom(peersWarningTxBuyerInputPartialSignature))
                 .setPeersWarningTxSellerInputPartialSignature(ByteString.copyFrom(peersWarningTxSellerInputPartialSignature))
-                .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature))
-                .setSwapTxInputPartialSignature(ByteString.copyFrom(swapTxInputPartialSignature));
+                .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature));
+        swapTxInputPartialSignature.ifPresent(e -> builder.setSwapTxInputPartialSignature(ByteString.copyFrom(e)));
+        return builder;
     }
 
     @Override
@@ -68,17 +81,20 @@ public static PartialSignaturesMessage fromProto(bisq.trade.protobuf.PartialSign
         return new PartialSignaturesMessage(proto.getPeersWarningTxBuyerInputPartialSignature().toByteArray(),
                 proto.getPeersWarningTxSellerInputPartialSignature().toByteArray(),
                 proto.getPeersRedirectTxInputPartialSignature().toByteArray(),
-                proto.getSwapTxInputPartialSignature().toByteArray());
+                proto.hasSwapTxInputPartialSignature()
+                        ? Optional.of(proto.getSwapTxInputPartialSignature().toByteArray())
+                        : Optional.empty());
     }
 
     @Override
     public boolean equals(Object o) {
+        if (this == o) return true;
         if (!(o instanceof PartialSignaturesMessage that)) return false;
 
         return Arrays.equals(peersWarningTxBuyerInputPartialSignature, that.peersWarningTxBuyerInputPartialSignature) &&
                 Arrays.equals(peersWarningTxSellerInputPartialSignature, that.peersWarningTxSellerInputPartialSignature) &&
                 Arrays.equals(peersRedirectTxInputPartialSignature, that.peersRedirectTxInputPartialSignature) &&
-                Arrays.equals(swapTxInputPartialSignature, that.swapTxInputPartialSignature);
+                OptionalUtils.optionalByteArrayEquals(swapTxInputPartialSignature, that.swapTxInputPartialSignature);
     }
 
     @Override
@@ -86,7 +102,7 @@ public int hashCode() {
         int result = Arrays.hashCode(peersWarningTxBuyerInputPartialSignature);
         result = 31 * result + Arrays.hashCode(peersWarningTxSellerInputPartialSignature);
         result = 31 * result + Arrays.hashCode(peersRedirectTxInputPartialSignature);
-        result = 31 * result + Arrays.hashCode(swapTxInputPartialSignature);
+        result = 31 * result + swapTxInputPartialSignature.map(Arrays::hashCode).orElse(0);
         return result;
     }
 }
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
index f1d53355d1..97ba457a4e 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
@@ -18,22 +18,27 @@
 package bisq.trade.mu_sig.messages.network;
 
 import bisq.network.identity.NetworkId;
-import lombok.EqualsAndHashCode;
+import com.google.protobuf.ByteString;
 import lombok.Getter;
 import lombok.ToString;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.Arrays;
+
 @Slf4j
 @ToString(callSuper = true)
 @Getter
-@EqualsAndHashCode(callSuper = true)
 public final class MuSigPaymentInitiatedMessage_E extends MuSigTradeMessage {
+    private final byte[] swapTxInputPartialSignature;
+
     public MuSigPaymentInitiatedMessage_E(String id,
                                           String tradeId,
                                           String protocolVersion,
                                           NetworkId sender,
-                                          NetworkId receiver) {
+                                          NetworkId receiver,
+                                          byte[] swapTxInputPartialSignature) {
         super(id, tradeId, protocolVersion, sender, receiver);
+        this.swapTxInputPartialSignature = swapTxInputPartialSignature;
 
         verify();
     }
@@ -55,7 +60,8 @@ private bisq.trade.protobuf.MuSigPaymentInitiatedMessage_E toMuSigPaymentInitiat
     }
 
     private bisq.trade.protobuf.MuSigPaymentInitiatedMessage_E.Builder getMuSigPaymentInitiatedMessage_E(boolean serializeForHash) {
-        return bisq.trade.protobuf.MuSigPaymentInitiatedMessage_E.newBuilder();
+        return bisq.trade.protobuf.MuSigPaymentInitiatedMessage_E.newBuilder()
+                .setSwapTxInputPartialSignature(ByteString.copyFrom(swapTxInputPartialSignature));
     }
 
     public static MuSigPaymentInitiatedMessage_E fromProto(bisq.trade.protobuf.TradeMessage proto) {
@@ -65,11 +71,27 @@ public static MuSigPaymentInitiatedMessage_E fromProto(bisq.trade.protobuf.Trade
                 proto.getTradeId(),
                 proto.getProtocolVersion(),
                 NetworkId.fromProto(proto.getSender()),
-                NetworkId.fromProto(proto.getReceiver()));
+                NetworkId.fromProto(proto.getReceiver()),
+                muSigMessageProto.getSwapTxInputPartialSignature().toByteArray());
     }
 
     @Override
     public double getCostFactor() {
         return getCostFactor(0.1, 0.3);
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof MuSigPaymentInitiatedMessage_E that)) return false;
+        if (!super.equals(o)) return false;
+
+        return Arrays.equals(swapTxInputPartialSignature, that.swapTxInputPartialSignature);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + Arrays.hashCode(swapTxInputPartialSignature);
+        return result;
+    }
 }
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java
index e3b3677bbd..f5032e8e75 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java
@@ -19,7 +19,7 @@
 
 import bisq.network.identity.NetworkId;
 import bisq.trade.mu_sig.messages.network.vo.NonceShares;
-import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -31,7 +31,7 @@
 @EqualsAndHashCode(callSuper = true)
 public final class MuSigSetupTradeMessage_C extends MuSigTradeMessage {
     private final NonceShares nonceShares;
-    private final PartialSignatures partialSignatures;
+    private final RedactedPartialSignatures redactedPartialSignatures;
 
     public MuSigSetupTradeMessage_C(String id,
                                     String tradeId,
@@ -39,10 +39,10 @@ public MuSigSetupTradeMessage_C(String id,
                                     NetworkId sender,
                                     NetworkId receiver,
                                     NonceShares nonceShares,
-                                    PartialSignatures partialSignatures) {
+                                    RedactedPartialSignatures redactedPartialSignatures) {
         super(id, tradeId, protocolVersion, sender, receiver);
         this.nonceShares = nonceShares;
-        this.partialSignatures = partialSignatures;
+        this.redactedPartialSignatures = redactedPartialSignatures;
 
         verify();
     }
@@ -66,7 +66,7 @@ private bisq.trade.protobuf.MuSigSetupTradeMessage_C toMuSigSetupTradeMessage_CP
     private bisq.trade.protobuf.MuSigSetupTradeMessage_C.Builder getMuSigSetupTradeMessage_C(boolean serializeForHash) {
         return bisq.trade.protobuf.MuSigSetupTradeMessage_C.newBuilder()
                 .setNonceShares(nonceShares.toProto(serializeForHash))
-                .setPartialSignatures(partialSignatures.toProto(serializeForHash));
+                .setRedactedPartialSignatures(redactedPartialSignatures.toProto(serializeForHash));
     }
 
     public static MuSigSetupTradeMessage_C fromProto(bisq.trade.protobuf.TradeMessage proto) {
@@ -78,7 +78,7 @@ public static MuSigSetupTradeMessage_C fromProto(bisq.trade.protobuf.TradeMessag
                 NetworkId.fromProto(proto.getSender()),
                 NetworkId.fromProto(proto.getReceiver()),
                 NonceShares.fromProto(muSigMessageProto.getNonceShares()),
-                PartialSignatures.fromProto(muSigMessageProto.getPartialSignatures()));
+                RedactedPartialSignatures.fromProto(muSigMessageProto.getRedactedPartialSignatures()));
     }
 
     @Override
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java
index dc2a1a1265..e3a0b192d0 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java
@@ -29,8 +29,8 @@
 import bisq.trade.mu_sig.messages.network.MuSigSetupTradeMessage_B;
 import bisq.trade.mu_sig.messages.network.MuSigSetupTradeMessage_C;
 import bisq.trade.mu_sig.messages.network.vo.NonceShares;
-import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
 import bisq.trade.mu_sig.messages.network.vo.PubKeyShares;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import bisq.trade.protobuf.NonceSharesRequest;
 import bisq.trade.protobuf.PartialSignaturesRequest;
 import bisq.trade.protobuf.ReceiverAddressAndAmount;
@@ -105,17 +105,16 @@ protected void commit() {
     @Override
     protected void sendMessage() {
         NonceShares nonceShares = NonceShares.from(myNonceSharesMessage);
-
-        // TODO redacting swapTxInputPartialSignature fails at MuSigPaymentReceiptConfirmedEventHandler
-        PartialSignatures partialSignatures =  PartialSignatures.from(myPartialSignaturesMessage);
-
+        // We do not expose swapTxInputPartialSignature at that stage to the peer, thus we use RedactedPartialSignatures
+        // Later once we initiate the payment we send the swapTxInputPartialSignature
+        RedactedPartialSignatures redactedPartialSignatures = RedactedPartialSignatures.from(myPartialSignaturesMessage);
         send(new MuSigSetupTradeMessage_C(StringUtils.createUid(),
                 trade.getId(),
                 trade.getProtocolVersion(),
                 trade.getMyself().getNetworkId(),
                 trade.getPeer().getNetworkId(),
                 nonceShares,
-                partialSignatures));
+                redactedPartialSignatures));
     }
 
     @Override
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java
index 7bf8f64aee..971c091626 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java
@@ -19,12 +19,17 @@
 
 import bisq.trade.ServiceProvider;
 import bisq.trade.mu_sig.MuSigTrade;
+import bisq.trade.mu_sig.MuSigTradeParty;
 import bisq.trade.mu_sig.handler.MuSigTradeMessageHandler;
 import bisq.trade.mu_sig.messages.network.MuSigPaymentInitiatedMessage_E;
+import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public final class MuSigPaymentInitiatedMessage_E_Handler extends MuSigTradeMessageHandler<MuSigTrade, MuSigPaymentInitiatedMessage_E> {
+    private byte[] peersSwapTxInputPartialSignature;
+
     public MuSigPaymentInitiatedMessage_E_Handler(ServiceProvider serviceProvider, MuSigTrade model) {
         super(serviceProvider, model);
     }
@@ -35,10 +40,16 @@ protected void verify(MuSigPaymentInitiatedMessage_E message) {
 
     @Override
     protected void process(MuSigPaymentInitiatedMessage_E message) {
+        peersSwapTxInputPartialSignature = message.getSwapTxInputPartialSignature();
     }
 
     @Override
     protected void commit() {
+        MuSigTradeParty peer = trade.getPeer();
+        // Now we reconstruct the un-redacted PartialSignatures
+        RedactedPartialSignatures redactedPartialSignatures = peer.getPeersRedactedPartialSignatures().orElseThrow();
+        PartialSignatures peersPartialSignatures = PartialSignatures.from(redactedPartialSignatures, peersSwapTxInputPartialSignature);
+        peer.setPeersPartialSignatures(peersPartialSignatures);
     }
 
     @Override
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java
index 8b61525d07..beda4495f4 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java
@@ -30,6 +30,7 @@
 import bisq.trade.mu_sig.messages.network.MuSigSetupTradeMessage_D;
 import bisq.trade.mu_sig.messages.network.vo.NonceShares;
 import bisq.trade.mu_sig.messages.network.vo.PartialSignatures;
+import bisq.trade.mu_sig.messages.network.vo.RedactedPartialSignatures;
 import bisq.trade.protobuf.DepositTxSignatureRequest;
 import bisq.trade.protobuf.PartialSignaturesRequest;
 import bisq.trade.protobuf.ReceiverAddressAndAmount;
@@ -43,7 +44,7 @@
 public final class MuSigSetupTradeMessage_C_Handler extends MuSigTradeMessageHandlerAsMessageSender<MuSigTrade, MuSigSetupTradeMessage_C> {
     private NonceShares peersNonceShares;
     private PartialSignaturesMessage myPartialSignaturesMessage;
-    private PartialSignatures peersPartialSignatures;
+    private RedactedPartialSignatures peersRedactedPartialSignatures;
     private DepositPsbt myDepositPsbt;
 
     public MuSigSetupTradeMessage_C_Handler(ServiceProvider serviceProvider, MuSigTrade model) {
@@ -57,10 +58,9 @@ protected void verify(MuSigSetupTradeMessage_C message) {
     @Override
     protected void process(MuSigSetupTradeMessage_C message) {
         peersNonceShares = message.getNonceShares();
-        peersPartialSignatures = message.getPartialSignatures();
+        peersRedactedPartialSignatures = message.getRedactedPartialSignatures();
 
-
-        NonceSharesMessage peersNonceSharesMessage =  NonceSharesMessage.from(peersNonceShares);
+        NonceSharesMessage peersNonceSharesMessage = NonceSharesMessage.from(peersNonceShares);
 
         PartialSignaturesRequest partialSignaturesRequest = PartialSignaturesRequest.newBuilder()
                 .setTradeId(trade.getId())
@@ -69,20 +69,12 @@ protected void process(MuSigSetupTradeMessage_C message) {
                 .build();
         myPartialSignaturesMessage = PartialSignaturesMessage.fromProto(musigBlockingStub.getPartialSignatures(partialSignaturesRequest));
 
-        PartialSignaturesMessage peersPartialSignaturesMessage =  PartialSignaturesMessage.from(peersPartialSignatures);
-
-        // TODO
-        //       @stejbac: redacting would make sense at senders side, but then it fails at MuSigPaymentReceiptConfirmedEventHandler.
-        //       if swapTxInputPartialSignature is empty byte array (redacted by the peer),
-        //       passing that to setPeersPartialSignatures results in a backend error.
-        //       Currently redaction is done on the sellers side, with clearSwapTxInputPartialSignature which results in
-        //       ByteString.EMPTY.
-        var signaturesProto = peersPartialSignaturesMessage.toProto(true)
-                .toBuilder()
-                .clearSwapTxInputPartialSignature();
+        // swapTxInputPartialSignature is not set in peersRedactedPartialSignatures, thus the
+        // PartialSignaturesMessage has a cleared swapTxInputPartialSignature field.
+        PartialSignaturesMessage peersRedactedPartialSignaturesMessage = PartialSignaturesMessage.from(peersRedactedPartialSignatures);
         DepositTxSignatureRequest depositTxSignatureRequest = DepositTxSignatureRequest.newBuilder()
                 .setTradeId(trade.getId())
-                .setPeersPartialSignatures(signaturesProto)
+                .setPeersPartialSignatures(peersRedactedPartialSignaturesMessage.toProto(true))
                 .build();
         myDepositPsbt = DepositPsbt.fromProto(musigBlockingStub.signDepositTx(depositTxSignatureRequest));
 
@@ -113,12 +105,12 @@ protected void commit() {
         mySelf.setMyDepositPsbt(myDepositPsbt);
 
         peer.setPeersNonceShares(peersNonceShares);
-        peer.setPeersPartialSignatures(peersPartialSignatures);
+        peer.setPeersRedactedPartialSignatures(peersRedactedPartialSignatures);
     }
 
     @Override
     protected void sendMessage() {
-        PartialSignatures partialSignatures =  PartialSignatures.from(myPartialSignaturesMessage);
+        PartialSignatures partialSignatures = PartialSignatures.from(myPartialSignaturesMessage);
 
         send(new MuSigSetupTradeMessage_D(StringUtils.createUid(),
                 trade.getId(),
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
index 987e68be5f..6428171d25 100644
--- a/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
@@ -23,28 +23,43 @@
 import lombok.Getter;
 
 import java.util.Arrays;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkArgument;
 
 @Getter
 public final class PartialSignatures implements Proto {
     public static PartialSignatures from(PartialSignaturesMessage partialSignaturesMessage) {
+        Optional<byte[]> swapTxInputPartialSignature = partialSignaturesMessage.getSwapTxInputPartialSignature();
+        checkArgument(swapTxInputPartialSignature.isPresent(),
+                "swapTxInputPartialSignature must not be empty when creating PartialSignatures from PartialSignaturesMessage");
         return new PartialSignatures(
                 partialSignaturesMessage.getPeersWarningTxBuyerInputPartialSignature().clone(),
                 partialSignaturesMessage.getPeersWarningTxSellerInputPartialSignature().clone(),
                 partialSignaturesMessage.getPeersRedirectTxInputPartialSignature().clone(),
-                partialSignaturesMessage.getSwapTxInputPartialSignature().clone()
+                swapTxInputPartialSignature.get().clone()
+        );
+    }
+
+    public static PartialSignatures from(RedactedPartialSignatures partialSignatures,
+                                         byte[] swapTxInputPartialSignature) {
+        return new PartialSignatures(
+                partialSignatures.getPeersWarningTxBuyerInputPartialSignature().clone(),
+                partialSignatures.getPeersWarningTxSellerInputPartialSignature().clone(),
+                partialSignatures.getPeersRedirectTxInputPartialSignature().clone(),
+                swapTxInputPartialSignature.clone()
         );
     }
 
     private final byte[] peersWarningTxBuyerInputPartialSignature;
     private final byte[] peersWarningTxSellerInputPartialSignature;
     private final byte[] peersRedirectTxInputPartialSignature;
-    // todo swapTxInputPartialSignature can be empty byte array (redacted), consider to make optional or make 2 classes
     private final byte[] swapTxInputPartialSignature;
 
     private PartialSignatures(byte[] peersWarningTxBuyerInputPartialSignature,
-                             byte[] peersWarningTxSellerInputPartialSignature,
-                             byte[] peersRedirectTxInputPartialSignature,
-                             byte[] swapTxInputPartialSignature) {
+                              byte[] peersWarningTxSellerInputPartialSignature,
+                              byte[] peersRedirectTxInputPartialSignature,
+                              byte[] swapTxInputPartialSignature) {
         this.peersWarningTxBuyerInputPartialSignature = peersWarningTxBuyerInputPartialSignature;
         this.peersWarningTxSellerInputPartialSignature = peersWarningTxSellerInputPartialSignature;
         this.peersRedirectTxInputPartialSignature = peersRedirectTxInputPartialSignature;
diff --git a/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java b/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java
new file mode 100644
index 0000000000..5f3748f9fd
--- /dev/null
+++ b/trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java
@@ -0,0 +1,84 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.trade.mu_sig.messages.network.vo;
+
+import bisq.common.proto.Proto;
+import bisq.trade.mu_sig.messages.grpc.PartialSignaturesMessage;
+import com.google.protobuf.ByteString;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+@Getter
+public final class RedactedPartialSignatures implements Proto {
+    public static RedactedPartialSignatures from(PartialSignaturesMessage partialSignaturesMessage) {
+        return new RedactedPartialSignatures(
+                partialSignaturesMessage.getPeersWarningTxBuyerInputPartialSignature().clone(),
+                partialSignaturesMessage.getPeersWarningTxSellerInputPartialSignature().clone(),
+                partialSignaturesMessage.getPeersRedirectTxInputPartialSignature().clone()
+        );
+    }
+
+    private final byte[] peersWarningTxBuyerInputPartialSignature;
+    private final byte[] peersWarningTxSellerInputPartialSignature;
+    private final byte[] peersRedirectTxInputPartialSignature;
+
+    private RedactedPartialSignatures(byte[] peersWarningTxBuyerInputPartialSignature,
+                                      byte[] peersWarningTxSellerInputPartialSignature,
+                                      byte[] peersRedirectTxInputPartialSignature) {
+        this.peersWarningTxBuyerInputPartialSignature = peersWarningTxBuyerInputPartialSignature;
+        this.peersWarningTxSellerInputPartialSignature = peersWarningTxSellerInputPartialSignature;
+        this.peersRedirectTxInputPartialSignature = peersRedirectTxInputPartialSignature;
+    }
+
+    @Override
+    public bisq.trade.protobuf.RedactedPartialSignatures.Builder getBuilder(boolean serializeForHash) {
+        return bisq.trade.protobuf.RedactedPartialSignatures.newBuilder()
+                .setPeersWarningTxBuyerInputPartialSignature(ByteString.copyFrom(peersWarningTxBuyerInputPartialSignature))
+                .setPeersWarningTxSellerInputPartialSignature(ByteString.copyFrom(peersWarningTxSellerInputPartialSignature))
+                .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature));
+    }
+
+    @Override
+    public bisq.trade.protobuf.RedactedPartialSignatures toProto(boolean serializeForHash) {
+        return getBuilder(serializeForHash).build();
+    }
+
+    public static RedactedPartialSignatures fromProto(bisq.trade.protobuf.RedactedPartialSignatures proto) {
+        return new RedactedPartialSignatures(proto.getPeersWarningTxBuyerInputPartialSignature().toByteArray(),
+                proto.getPeersWarningTxSellerInputPartialSignature().toByteArray(),
+                proto.getPeersRedirectTxInputPartialSignature().toByteArray());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof RedactedPartialSignatures that)) return false;
+
+        return Arrays.equals(peersWarningTxBuyerInputPartialSignature, that.peersWarningTxBuyerInputPartialSignature) &&
+                Arrays.equals(peersWarningTxSellerInputPartialSignature, that.peersWarningTxSellerInputPartialSignature) &&
+                Arrays.equals(peersRedirectTxInputPartialSignature, that.peersRedirectTxInputPartialSignature);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Arrays.hashCode(peersWarningTxBuyerInputPartialSignature);
+        result = 31 * result + Arrays.hashCode(peersWarningTxSellerInputPartialSignature);
+        result = 31 * result + Arrays.hashCode(peersRedirectTxInputPartialSignature);
+        return result;
+    }
+}
diff --git a/trade/src/main/proto/trade.proto b/trade/src/main/proto/trade.proto
index d1f5f2fe47..dfe3b558cb 100644
--- a/trade/src/main/proto/trade.proto
+++ b/trade/src/main/proto/trade.proto
@@ -176,6 +176,12 @@ message PartialSignatures {
   optional bytes swapTxInputPartialSignature = 4;
 }
 
+message RedactedPartialSignatures {
+  bytes peersWarningTxBuyerInputPartialSignature = 1;
+  bytes peersWarningTxSellerInputPartialSignature = 2;
+  bytes peersRedirectTxInputPartialSignature = 3;
+}
+
 
 message SwapTxSignature {
   bytes swapTx = 1;
@@ -190,7 +196,8 @@ message MuSigTradeParty {
   optional  NonceShares peersNonceShares = 4;
   optional musigrpc.PartialSignaturesMessage myPartialSignaturesMessage = 5;
   optional PartialSignatures peersPartialSignatures = 6;
-  optional musigrpc.DepositPsbt myDepositPsbt = 7;
+  optional RedactedPartialSignatures peersRedactedPartialSignatures = 7;
+  optional musigrpc.DepositPsbt myDepositPsbt = 8;
   optional musigrpc.SwapTxSignatureResponse mySwapTxSignatureResponse = 9;
   optional SwapTxSignature peersSwapTxSignature = 10;
   optional musigrpc.CloseTradeResponse myCloseTradeResponse = 11;
@@ -235,7 +242,7 @@ message MuSigSetupTradeMessage_B {
 
 message MuSigSetupTradeMessage_C {
   NonceShares nonceShares = 1;
-  PartialSignatures partialSignatures = 2;
+  RedactedPartialSignatures redactedPartialSignatures = 2;
 }
 
 message MuSigSetupTradeMessage_D {
@@ -243,7 +250,7 @@ message MuSigSetupTradeMessage_D {
 }
 
 message MuSigPaymentInitiatedMessage_E {
-  // no additional fields; all data inherited from base class
+  bytes swapTxInputPartialSignature = 1;
 }
 
 message MuSigPaymentReceivedMessage_F {


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java (1)</summary><blockquote>

`48-52`: **Commit method updated to reconstruct full PartialSignatures**

The commit method now properly:
1. Retrieves the peer's redacted partial signatures
2. Reconstructs the full PartialSignatures using the static factory method
3. Sets the reconstructed signatures on the peer party

Consider adding a custom message to the `orElseThrow()` call to improve debugging if it fails.


```diff
-        RedactedPartialSignatures redactedPartialSignatures = peer.getPeersRedactedPartialSignatures().orElseThrow();
+        RedactedPartialSignatures redactedPartialSignatures = peer.getPeersRedactedPartialSignatures()
+                .orElseThrow(() -> new IllegalStateException("Missing peer's redacted partial signatures"));
```

</blockquote></details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java (1)</summary><blockquote>

`72-74`: **Comment updated and variable created for redacted partial signatures message**

The comments have been updated to reflect the new redacted partial signatures approach. However, there's a minor naming inconsistency in the variable name.

```diff
-        PartialSignaturesMessage peersredactedPartialSignaturesMessage = PartialSignaturesMessage.from(peersRedactedPartialSignatures);
+        PartialSignaturesMessage peersRedactedPartialSignaturesMessage = PartialSignaturesMessage.from(peersRedactedPartialSignatures);
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between eb188c2af391ef5082c2a1709421e666a94d9c38 and 2d5805aa91d41eed380857311deeba33f15a968c.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java` (7 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java` (2 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java` (0 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java` (3 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java` (4 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java` (4 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java` (2 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java` (2 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java` (5 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java` (1 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java` (1 hunks)
* `trade/src/main/proto/trade.proto` (3 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (15)</summary>

* GitHub Check: Build tor module on macOS-latest / Build tor module on macOS-latest
* GitHub Check: Build wallet module on windows-latest / Build wallet module on windows-latest
* GitHub Check: Build wallet module on ubuntu-latest / Build wallet module on ubuntu-latest
* GitHub Check: Build tor module on ubuntu-latest / Build tor module on ubuntu-latest
* GitHub Check: Build wallet module on macOS-latest / Build wallet module on macOS-latest
* GitHub Check: Build tor module on windows-latest / Build tor module on windows-latest
* GitHub Check: Build network module on macOS-latest / Build network module on macOS-latest
* GitHub Check: Build network module on ubuntu-latest / Build network module on ubuntu-latest
* GitHub Check: Build Bisq on windows-latest / Build Bisq on windows-latest
* GitHub Check: Build Bisq on ubuntu-latest / Build Bisq on ubuntu-latest
* GitHub Check: Build network module on windows-latest / Build network module on windows-latest
* GitHub Check: Build Bisq on macOS-latest / Build Bisq on macOS-latest
* GitHub Check: Build apps module on ubuntu-latest / Build apps module on ubuntu-latest
* GitHub Check: Build apps module on windows-latest / Build apps module on windows-latest
* GitHub Check: Build apps module on macOS-latest / Build apps module on macOS-latest

</details>

<details>
<summary>🔇 Additional comments (48)</summary><blockquote>

<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java (3)</summary>

`25-25`: **LGTM: Added import for PartialSignatures.**

The import has been correctly added to support the new functionality for handling partial signatures.

---

`43-44`: **LGTM: Extraction of swapTxInputPartialSignature.**

This code correctly extracts the PartialSignatures object from the trade's partial signatures message and retrieves the swapTxInputPartialSignature byte array that will be sent separately to the peer.

---

`49-50`: **LGTM: Updated message constructor call.**

The MuSigPaymentInitiatedMessage_E constructor is now correctly called with the additional swapTxInputPartialSignature parameter, aligning with the security enhancement to only share sensitive signature components at the correct protocol stage.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java (4)</summary>

`33-33`: **LGTM: Updated import for RedactedPartialSignatures.**

Replaced the import of PartialSignatures with RedactedPartialSignatures to support the updated protocol flow.

---

`108-110`: **LGTM: Clear documentation of security enhancement.**

Excellent comments explaining the security rationale behind not exposing the swapTxInputPartialSignature at this stage of the protocol, with a clear indication of when it will be sent later.

---

`111-111`: **LGTM: Using RedactedPartialSignatures.**

Correctly creates a RedactedPartialSignatures object from myPartialSignaturesMessage instead of using the full PartialSignatures object, implementing the security enhancement.

---

`117-117`: **LGTM: Updated message constructor parameter.**

The MuSigSetupTradeMessage_C constructor now correctly receives redactedPartialSignatures instead of the full partial signatures, aligning with the protocol update.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java (2)</summary>

`38-46`: **LGTM: New factory method for reconstructing full signatures.**

Added a well-implemented factory method to reconstruct full PartialSignatures from RedactedPartialSignatures and a separate swapTxInputPartialSignature. The implementation correctly clones all byte arrays to maintain immutability.

---

`54-57`: **LGTM: Constructor parameter formatting.**

Minor reformatting of the constructor parameter list improves readability while maintaining the same functionality.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java (3)</summary>

`22-22`: **LGTM: Added import for RedactedPartialSignatures.**

The import has been correctly added to support the new functionality for handling redacted partial signatures.

---

`39-46`: **LGTM: New factory method for redacted signatures.**

Added a well-implemented factory method to create a PartialSignaturesMessage from RedactedPartialSignatures, correctly initializing the swapTxInputPartialSignature field with an empty byte array.

---

`65-77`: **LGTM: Improved builder handling for empty byte arrays.**

The getBuilder method has been refactored to properly handle empty byte arrays by clearing the swapTxInputPartialSignature field, preventing backend errors. The detailed comment explains the rationale clearly.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java (5)</summary>

`22-22`: **Import updated to use RedactedPartialSignatures**

The import has been correctly updated to use the new `RedactedPartialSignatures` class instead of `PartialSignatures`.

---

`34-34`: **Field type correctly changed to RedactedPartialSignatures**

The field has been properly updated to use the new redacted type, which aligns with the PR objective of handling redacted partial signatures.

---

`42-45`: **Constructor parameter and assignment updated for RedactedPartialSignatures**

The constructor parameter and field assignment have been correctly updated to use the new `RedactedPartialSignatures` type.

---

`69-69`: **Serialization method correctly updated for RedactedPartialSignatures**

The protobuf serialization method now properly uses the redacted partial signatures.

---

`81-81`: **Deserialization correctly updated to use RedactedPartialSignatures**

The static `fromProto` method has been properly updated to use the new `RedactedPartialSignatures` type.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java (3)</summary>

`22-26`: **Imports correctly updated for both signature types**

The imports have been properly updated to include both `PartialSignatures` and `RedactedPartialSignatures` classes.

---

`31-31`: **New field added for storing the swap transaction input partial signature**

A new field has been correctly added to store the sensitive signature component that will be received separately.

---

`43-43`: **Process method updated to store the swap transaction input partial signature**

The process method now correctly extracts and stores the swap transaction input partial signature from the message.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java (5)</summary>

`21-21`: **Import added for ByteString**

The import for `ByteString` has been correctly added to support serialization of the new byte array field.

---

`32-32`: **New field added for swap transaction input partial signature**

A new field has been correctly added to store the sensitive signature component.

---

`38-41`: **Constructor updated to include the new field**

The constructor has been properly updated to accept and store the new field.

---

`63-64`: **Serialization method updated to include the new field**

The protobuf serialization method now correctly includes the swap transaction input partial signature using `ByteString.copyFrom`.

---

`74-75`: **Deserialization updated to extract the new field**

The static `fromProto` method has been properly updated to extract the swap transaction input partial signature.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java (6)</summary>

`33-33`: **Import added for RedactedPartialSignatures**

The import for `RedactedPartialSignatures` has been correctly added.

---

`47-47`: **Field type updated to RedactedPartialSignatures**

The field has been properly updated to use the new redacted type.

---

`61-61`: **Process method updated to use redacted partial signatures**

The process method now correctly uses `getRedactedPartialSignatures()` instead of `getPartialSignatures()`.

---

`77-77`: **DepositTxSignatureRequest builder updated to use redacted partial signatures**

The builder now correctly uses the redacted partial signatures for the deposit transaction signature request.

---

`108-108`: **Commit method updated to set redacted partial signatures**

The commit method now correctly sets the redacted partial signatures on the peer.

---

`113-113`: **Factory method used to create PartialSignatures**

The code correctly uses the factory method to create `PartialSignatures` from `myPartialSignaturesMessage`.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java (7)</summary>

`32-32`: **Clean import of the new RedactedPartialSignatures class.**

This import correctly adds the newly introduced RedactedPartialSignatures class for use in this file.

---

`50-50`: **New field for storing redacted partial signatures.**

Good addition of an Optional field to store the peer's redacted partial signatures, following the same pattern as other cryptographic components in this class.

---

`68-68`: **Constructor parameter added correctly.**

The constructor parameter for the new field is added in a consistent position with the rest of the parameters.

---

`82-82`: **Field initialization in constructor.**

Proper assignment of the constructor parameter to the field, maintaining consistency with other field initializations.

---

`99-99`: **Serialization support for the new field.**

The serialization logic correctly handles the new field when building the protobuf message.

---

`130-132`: **Deserialization support for the new field.**

The deserialization logic properly checks for and extracts the new field from the protobuf message.

---

`175-177`: **Setter method for the new field.**

The setter method follows the same pattern as other setters in this class, wrapping the value in Optional.of().

</details>
<details>
<summary>trade/src/main/proto/trade.proto (4)</summary>

`179-183`: **Well-structured definition of the new RedactedPartialSignatures message.**

The RedactedPartialSignatures message is properly defined with fields for storing the three types of partial signatures that can be safely shared earlier in the protocol.

---

`199-200`: **Update to MuSigTradeParty message fields.**

Good field management in the protobuf definition:
1. The new peersRedactedPartialSignatures field replaces myDepositPsbt at position 7
2. myDepositPsbt is properly moved to position 8

This change maintains backward compatibility while adding the new field.

---

`245-245`: **Message field type change for MuSigSetupTradeMessage_C.**

The field is correctly changed from PartialSignatures to RedactedPartialSignatures, reflecting the design change to use redacted signatures during the setup phase.

---

`253-253`: **Added swapTxInputPartialSignature field to MuSigPaymentInitiatedMessage_E.**

This change allows the swap transaction input signature to be sent separately in the payment initiated message, complementing the redacted signatures approach.

</details>
<details>
<summary>trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java (6)</summary>

`1-28`: **Well-structured class setup for the new RedactedPartialSignatures value object.**

The class is properly defined as a final immutable value object implementing the Proto interface, with appropriate imports and annotations.

---

`29-35`: **Factory method implementation for creating from PartialSignaturesMessage.**

The factory method correctly extracts and clones the relevant byte arrays from the source PartialSignaturesMessage, ensuring proper encapsulation.

---

`37-47`: **Clean field declaration and constructor implementation.**

The fields are properly declared as final byte arrays, and the constructor correctly initializes them from the provided parameters.

---

`49-60`: **Proper protobuf serialization support.**

The implementation correctly handles serialization to protobuf format by implementing both getBuilder and toProto methods.

---

`62-66`: **Correct protobuf deserialization implementation.**

The static fromProto method properly converts from the protobuf representation back to the domain object.

---

`68-83`: **Proper equals and hashCode implementation for byte arrays.**

The equals and hashCode methods correctly use Arrays.equals and Arrays.hashCode for comparing byte arrays, which is essential since the default equals would only compare references.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-22T14:32:12Z
user: login: stejbac
body: The changes look OK (and don't give any obvious errors testing against the Rust server), aside from the missed reference equality bug in `equals`/`hashCode` and the minor local variable casing typo, as indicated.

I probably should have added a buyer-as-maker/seller-as-taker trade test/example to `TradeProtocolClient` in the bisq-musig project. In that case, it would be the seller sending Message C and leaving the `swapTxInputPartialSignature` field in, the buyer sending Message D and leaving it out, and then the seller broadcasting the deposit tx (so the taker would always be the one who broadcasts it, as opposed to the seller in bisq1). So with the changes in this PR making `PartialSignatures` and `RedactedPartialSignatures` separate proto types, it may create the small complication of requiring two different versions of Message C and two different versions of Message D when the buyer-as-maker/seller-as-taker path is implemented. Of course, if an entirely distinct set of Messages A, B, C, D would be used anyway, then that won't be an issue.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T00:55:16Z
user: login: HenrikJannsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T10:37:25Z
user: login: HenrikJannsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T10:38:10Z
user: login: HenrikJannsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T10:55:04Z
user: login: HenrikJannsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T11:04:54Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>common/src/main/java/bisq/common/util/OptionalUtils.java (1)</summary><blockquote>

`16-20`: **Add null safety and consider documentation improvements.**

The method logic is correct for comparing `Optional<byte[]>` instances by value. However, consider these improvements:

1. **Null Safety**: The method doesn't handle null inputs and will throw `NullPointerException`
2. **Documentation**: Consider adding JavaDoc to explain the behavior and null handling



```diff
+    /**
+     * Compares two Optional<byte[]> instances by their byte array contents.
+     * @param a first optional byte array (must not be null)
+     * @param b second optional byte array (must not be null) 
+     * @return true if both are empty or both contain equal byte arrays
+     * @throws NullPointerException if either parameter is null
+     */
     public static boolean optionalByteArrayEquals(Optional<byte[]> a, Optional<byte[]> b) {
+        if (a == null || b == null) {
+            throw new IllegalArgumentException("Optional parameters must not be null");
+        }
         return a.isPresent() == b.isPresent() &&
                 (a.isEmpty() || Arrays.equals(a.get(), b.get()));
     }
```

Alternatively, if null inputs should be handled gracefully:

```diff
     public static boolean optionalByteArrayEquals(Optional<byte[]> a, Optional<byte[]> b) {
+        if (a == null && b == null) return true;
+        if (a == null || b == null) return false;
         return a.isPresent() == b.isPresent() &&
                 (a.isEmpty() || Arrays.equals(a.get(), b.get()));
     }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2d5805aa91d41eed380857311deeba33f15a968c and 6c96c3ad56908396a931ab80bccb1077d2bb0757.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `common/src/main/java/bisq/common/util/OptionalUtils.java` (2 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java` (4 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java` (3 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java` (5 hunks)
* `trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
* trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java
* trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
* trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (15)</summary>

* GitHub Check: Build tor module on windows-latest / Build tor module on windows-latest
* GitHub Check: Build wallet module on windows-latest / Build wallet module on windows-latest
* GitHub Check: Build tor module on macOS-latest / Build tor module on macOS-latest
* GitHub Check: Build wallet module on macOS-latest / Build wallet module on macOS-latest
* GitHub Check: Build tor module on ubuntu-latest / Build tor module on ubuntu-latest
* GitHub Check: Build network module on ubuntu-latest / Build network module on ubuntu-latest
* GitHub Check: Build wallet module on ubuntu-latest / Build wallet module on ubuntu-latest
* GitHub Check: Build network module on macOS-latest / Build network module on macOS-latest
* GitHub Check: Build network module on windows-latest / Build network module on windows-latest
* GitHub Check: Build Bisq on windows-latest / Build Bisq on windows-latest
* GitHub Check: Build Bisq on macOS-latest / Build Bisq on macOS-latest
* GitHub Check: Build Bisq on ubuntu-latest / Build Bisq on ubuntu-latest
* GitHub Check: Build apps module on windows-latest / Build apps module on windows-latest
* GitHub Check: Build apps module on macOS-latest / Build apps module on macOS-latest
* GitHub Check: Build apps module on ubuntu-latest / Build apps module on ubuntu-latest

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>common/src/main/java/bisq/common/util/OptionalUtils.java (1)</summary>

`3-3`: **LGTM: Import correctly added.**

The `Arrays` import is appropriately added to support the new `optionalByteArrayEquals` method.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-23T11:07:53Z

Review comments:
diff_hunk: @@ -69,20 +69,12 @@ protected void process(MuSigSetupTradeMessage_C message) {
                 .build();
         myPartialSignaturesMessage = PartialSignaturesMessage.fromProto(musigBlockingStub.getPartialSignatures(partialSignaturesRequest));
 
-        PartialSignaturesMessage peersPartialSignaturesMessage =  PartialSignaturesMessage.from(peersPartialSignatures);
-
-        // TODO
-        //       @stejbac: redacting would make sense at senders side, but then it fails at MuSigPaymentReceiptConfirmedEventHandler.
-        //       if swapTxInputPartialSignature is empty byte array (redacted by the peer),
-        //       passing that to setPeersPartialSignatures results in a backend error.
-        //       Currently redaction is done on the sellers side, with clearSwapTxInputPartialSignature which results in
-        //       ByteString.EMPTY.
-        var signaturesProto = peersPartialSignaturesMessage.toProto(true)
-                .toBuilder()
-                .clearSwapTxInputPartialSignature();
+        // swapTxInputPartialSignature is not set in peersRedactedPartialSignatures, thus the
+        // PartialSignaturesMessage has a cleared swapTxInputPartialSignature field.
+        PartialSignaturesMessage peersredactedPartialSignaturesMessage = PartialSignaturesMessage.from(peersRedactedPartialSignatures);
path: trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java
user: login: stejbac
body: Typo (case): Local variable should probably be named `peersRedactedPartialSignaturesMessage`.
created_at: 2025-05-22T23:24:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -35,16 +35,26 @@ public static PartialSignatures from(PartialSignaturesMessage partialSignaturesM
         );
     }
 
+    public static PartialSignatures from(RedactedPartialSignatures partialSignatures,
+                                         byte[] swapTxInputPartialSignature) {
+        return new PartialSignatures(
+                partialSignatures.getPeersWarningTxBuyerInputPartialSignature().clone(),
+                partialSignatures.getPeersWarningTxSellerInputPartialSignature().clone(),
+                partialSignatures.getPeersRedirectTxInputPartialSignature().clone(),
+                swapTxInputPartialSignature.clone()
+        );
+    }
+
     private final byte[] peersWarningTxBuyerInputPartialSignature;
     private final byte[] peersWarningTxSellerInputPartialSignature;
     private final byte[] peersRedirectTxInputPartialSignature;
     // todo swapTxInputPartialSignature can be empty byte array (redacted), consider to make optional or make 2 classes
path: trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
user: login: stejbac
body: Is this TODO still applicable, now that the `RedactedPartialSignatures` class has been added? (I guess that `b.t.m.m.n.v.PartialSignatures.swapTxInputPartialSignature` should never be empty/missing now.)
created_at: 2025-05-22T23:38:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -28,12 +29,16 @@
 @Getter
 @EqualsAndHashCode(callSuper = true)
 public final class MuSigPaymentInitiatedMessage_E extends MuSigTradeMessage {
+    private final byte[] swapTxInputPartialSignature;
path: trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
user: login: stejbac
body: By adding a byte array field, the Lombok `@EqualsAndHashCode` annotation should be replaced with a manual `equals`/`hashCode` implementation, as was done for the other such DTOs.
created_at: 2025-05-22T23:52:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,11 +62,19 @@ public PartialSignaturesMessage(byte[] peersWarningTxBuyerInputPartialSignature,
 
     @Override
     public bisq.trade.protobuf.PartialSignaturesMessage.Builder getBuilder(boolean serializeForHash) {
-        return bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
+        bisq.trade.protobuf.PartialSignaturesMessage.Builder builder = bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
                 .setPeersWarningTxBuyerInputPartialSignature(ByteString.copyFrom(peersWarningTxBuyerInputPartialSignature))
                 .setPeersWarningTxSellerInputPartialSignature(ByteString.copyFrom(peersWarningTxSellerInputPartialSignature))
                 .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature))
                 .setSwapTxInputPartialSignature(ByteString.copyFrom(swapTxInputPartialSignature));
+
+        // TODO  @stejbac: if swapTxInputPartialSignature is empty byte array,
path: trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
user: login: stejbac
body: In the corresponding `PartialSignaturesMessage` proto (defined in `rpc.proto`), I made the `swapTxInputPartialSignature` field an optional byte array, as it is intended to sometimes be missing (specifically, when the seller doesn't yet have a value to pass to the Rust server, at the trade start). I guess making the field non-optional in this class and using an empty byte array to represent 'missing' is OK, as obviously a valid partial signature will never be empty. But perhaps this class could also make the field optional, to exactly match the underlying proto, then maybe throw an `IllegalArgumentException` if converted into a `PartialSignatures` (as opposed to `RedactedPartialSignature`) instance (since the former is now intended specifically for the case where it isn't missing/empty). (I'm not sure offhand if the Java protobuf implementation is confusing 'empty' and 'missing' for `optional bytes` fields, or if the protobuf spec makes them indistinguishable -- I would presume not.)
created_at: 2025-05-23T00:30:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -35,16 +35,26 @@ public static PartialSignatures from(PartialSignaturesMessage partialSignaturesM
         );
     }
 
+    public static PartialSignatures from(RedactedPartialSignatures partialSignatures,
+                                         byte[] swapTxInputPartialSignature) {
+        return new PartialSignatures(
+                partialSignatures.getPeersWarningTxBuyerInputPartialSignature().clone(),
+                partialSignatures.getPeersWarningTxSellerInputPartialSignature().clone(),
+                partialSignatures.getPeersRedirectTxInputPartialSignature().clone(),
+                swapTxInputPartialSignature.clone()
+        );
+    }
+
     private final byte[] peersWarningTxBuyerInputPartialSignature;
     private final byte[] peersWarningTxSellerInputPartialSignature;
     private final byte[] peersRedirectTxInputPartialSignature;
     // todo swapTxInputPartialSignature can be empty byte array (redacted), consider to make optional or make 2 classes
path: trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java
user: login: HenrikJannsen
body: I will delete the TODO.
created_at: 2025-05-23T10:37:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -28,12 +29,16 @@
 @Getter
 @EqualsAndHashCode(callSuper = true)
 public final class MuSigPaymentInitiatedMessage_E extends MuSigTradeMessage {
+    private final byte[] swapTxInputPartialSignature;
path: trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java
user: login: HenrikJannsen
body: Ah thanks!
created_at: 2025-05-23T10:38:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,11 +62,19 @@ public PartialSignaturesMessage(byte[] peersWarningTxBuyerInputPartialSignature,
 
     @Override
     public bisq.trade.protobuf.PartialSignaturesMessage.Builder getBuilder(boolean serializeForHash) {
-        return bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
+        bisq.trade.protobuf.PartialSignaturesMessage.Builder builder = bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
                 .setPeersWarningTxBuyerInputPartialSignature(ByteString.copyFrom(peersWarningTxBuyerInputPartialSignature))
                 .setPeersWarningTxSellerInputPartialSignature(ByteString.copyFrom(peersWarningTxSellerInputPartialSignature))
                 .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature))
                 .setSwapTxInputPartialSignature(ByteString.copyFrom(swapTxInputPartialSignature));
+
+        // TODO  @stejbac: if swapTxInputPartialSignature is empty byte array,
path: trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
user: login: HenrikJannsen
body: Ah sorry missed that. Will make it optional as well.
created_at: 2025-05-23T10:55:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,11 +62,19 @@ public PartialSignaturesMessage(byte[] peersWarningTxBuyerInputPartialSignature,
 
     @Override
     public bisq.trade.protobuf.PartialSignaturesMessage.Builder getBuilder(boolean serializeForHash) {
-        return bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
+        bisq.trade.protobuf.PartialSignaturesMessage.Builder builder = bisq.trade.protobuf.PartialSignaturesMessage.newBuilder()
                 .setPeersWarningTxBuyerInputPartialSignature(ByteString.copyFrom(peersWarningTxBuyerInputPartialSignature))
                 .setPeersWarningTxSellerInputPartialSignature(ByteString.copyFrom(peersWarningTxSellerInputPartialSignature))
                 .setPeersRedirectTxInputPartialSignature(ByteString.copyFrom(peersRedirectTxInputPartialSignature))
                 .setSwapTxInputPartialSignature(ByteString.copyFrom(swapTxInputPartialSignature));
+
+        // TODO  @stejbac: if swapTxInputPartialSignature is empty byte array,
path: trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java
user: login: HenrikJannsen
body: I removed now also the following as the clearSwapTxInputPartialSignature seems to be not needed anymore when using optional.
```
 // TODO  @stejbac: if swapTxInputPartialSignature is empty byte array,
        //       passing that to setPeersPartialSignatures results in a backend error as it seems the backend expects
        //       ByteString.EMPTY. With clearSwapTxInputPartialSignature we get ByteString.EMPTY.
        if (swapTxInputPartialSignature.isEmpty() || swapTxInputPartialSignature.get().length == 0) {
            builder.clearSwapTxInputPartialSignature();
        }
```
created_at: 2025-05-23T11:04:54Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-22T14:29:29Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This change introduces a new `RedactedPartialSignatures` value object and updates multiple classes, messages, and protobuf definitions to use it instead of full partial signatures where appropriate. It also adds new fields and serialization logic for handling redacted and full partial signatures separately in the MuSig trade protocol, ensuring sensitive signature components are only exchanged at the correct protocol stage.

## Changes

| File(s)                                                                                                    | Change Summary |
|------------------------------------------------------------------------------------------------------------|---------------|
| `trade/src/main/java/bisq/trade/mu_sig/MuSigTradeParty.java`<br>`trade/src/main/proto/trade.proto`         | Added `peersRedactedPartialSignatures` field to `MuSigTradeParty` and corresponding protobuf message; updated constructor, serialization, and deserialization logic to support the new field. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/RedactedPartialSignatures.java`                 | Introduced new value object for redacted partial signatures, with protobuf serialization/deserialization, equality, and hash code methods. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/vo/PartialSignatures.java`                         | Added static factory method to construct a full `PartialSignatures` from a `RedactedPartialSignatures` and a swap input signature. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigSetupTradeMessage_C_Handler.java` | Switched from using `PartialSignatures` to `RedactedPartialSignatures` for peer signatures, updating field, method calls, and removing manual clearing of sensitive fields. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/buyer_as_taker/MuSigSetupTradeMessage_B_Handler.java` | Updated to send redacted partial signatures instead of full signatures in setup message. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigSetupTradeMessage_C.java`<br>`trade/src/main/proto/trade.proto` | Changed field and constructor to use `RedactedPartialSignatures` instead of `PartialSignatures`; updated serialization/deserialization. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/handler/seller_as_maker/MuSigPaymentInitiatedMessage_E_Handler.java` | Added logic to reconstruct and store full peer partial signatures by combining redacted signatures with the swap input signature from the message. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/network/MuSigPaymentInitiatedMessage_E.java`<br>`trade/src/main/proto/trade.proto` | Added `swapTxInputPartialSignature` field to message, updated constructor, serialization, and deserialization. |
| `trade/src/main/java/bisq/trade/mu_sig/events/buyer_as_taker/MuSigPaymentInitiatedEventHandler.java`        | Updated to include the swap transaction input partial signature in the initiated message payload. |
| `trade/src/main/java/bisq/trade/mu_sig/messages/grpc/PartialSignaturesMessage.java`                        | Added static factory for creating from `RedactedPartialSignatures`; improved handling of empty signature fields in protobuf serialization. |
| `trade/src/main/java/bisq/trade/mu_sig/events/seller_as_maker/MuSigPaymentReceiptConfirmedEventHandler.java`| Removed two explanatory comments; no logic changes. |
| `common/src/main/java/bisq/common/util/OptionalUtils.java`                                                | Added utility method to compare two `Optional<byte[]>` instances by value. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Buyer
    participant Seller
    participant Network

    Buyer->>Seller: MuSigSetupTradeMessage_C (with RedactedPartialSignatures)
    Seller->>Seller: Store peer's RedactedPartialSignatures
    Seller->>Buyer: MuSigPaymentInitiatedMessage_E (with swapTxInputPartialSignature)
    Buyer->>Seller: Receives swapTxInputPartialSignature
    Seller->>Seller: Reconstruct full PartialSignatures from RedactedPartialSignatures + swapTxInputPartialSignature
```

## Possibly related PRs

- [bisq-network/bisq2#3439](https://github.com/bisq-network/bisq2/pull/3439): Large-scale renaming and refactoring of MuSig-related classes and messages, which relates to the changes here by affecting the same protocol and message structures.

## Poem

> In the warren where signatures hide,  
> Redacted bytes now hop inside.  
> Full secrets kept until the end,  
> Only when it’s safe, we send.  
> Rabbits code with careful paws—  
> Privacy first, our favorite cause!  
> 🐇✨

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=bisq-network/bisq2&utm_content=3516):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: HenrikJannsen
created_at: 2025-05-22T14:32:42Z
body: @stejbac Could you have a look to that?
author_association: CONTRIBUTOR
user: login: HenrikJannsen
created_at: 2025-05-23T11:11:07Z
body: > I probably should have added a buyer-as-maker/seller-as-taker trade test/example to `TradeProtocolClient`

That would be great, then I can see better the differences. If the distinction of PartialSignatures/RedactedPartialSignatures cause too much extra complexity we might drop it and go back to the grpc message solution by using an optional field. 


author_association: CONTRIBUTOR