From 16b9192dada4c0c160688cd7b56c69d3c094cf83 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 9 Dec 2025 21:30:16 +0200 Subject: [PATCH] signrpc: implement combined nonce RPC server handlers Add server-side RPC handlers for MuSig2RegisterCombinedNonce and MuSig2GetCombinedNonce. The handlers: - Delegate to the Signer interface methods - Validate input (session ID format, combined nonce length) - Include macaroon permissions (generate for register, read for get) These handlers complete the server-side RPC implementation. --- lnrpc/signrpc/signer_server.go | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/lnrpc/signrpc/signer_server.go b/lnrpc/signrpc/signer_server.go index a98e24d1b..b0b161f13 100644 --- a/lnrpc/signrpc/signer_server.go +++ b/lnrpc/signrpc/signer_server.go @@ -86,6 +86,14 @@ var ( Entity: "signer", Action: "generate", }}, + "/signrpc.Signer/MuSig2RegisterCombinedNonce": {{ + Entity: "signer", + Action: "generate", + }}, + "/signrpc.Signer/MuSig2GetCombinedNonce": {{ + Entity: "signer", + Action: "read", + }}, "/signrpc.Signer/MuSig2Sign": {{ Entity: "signer", Action: "generate", @@ -1080,6 +1088,62 @@ func (s *Server) MuSig2RegisterNonces(_ context.Context, return &MuSig2RegisterNoncesResponse{HaveAllNonces: haveAllNonces}, nil } +// MuSig2RegisterCombinedNonce registers a pre-aggregated combined nonce for a +// session identified by its ID. This is an alternative to MuSig2RegisterNonces +// and is used when a coordinator has already aggregated all individual nonces. +func (s *Server) MuSig2RegisterCombinedNonce(_ context.Context, + in *MuSig2RegisterCombinedNonceRequest) ( + *MuSig2RegisterCombinedNonceResponse, error) { + + // Check session ID length. + sessionID, err := parseMuSig2SessionID(in.SessionId) + if err != nil { + return nil, fmt.Errorf("error parsing session ID: %w", err) + } + + // Validate the combined nonce length. + if len(in.CombinedPublicNonce) != musig2.PubNonceSize { + return nil, fmt.Errorf("invalid combined nonce length, got "+ + "%d wanted %d", len(in.CombinedPublicNonce), + musig2.PubNonceSize) + } + + // Convert to the expected fixed-size array. + var combinedNonce [musig2.PubNonceSize]byte + copy(combinedNonce[:], in.CombinedPublicNonce) + + // Register the combined nonce. + err = s.cfg.Signer.MuSig2RegisterCombinedNonce(sessionID, combinedNonce) + if err != nil { + return nil, fmt.Errorf("error registering combined nonce: %w", + err) + } + + return &MuSig2RegisterCombinedNonceResponse{}, nil +} + +// MuSig2GetCombinedNonce retrieves the combined nonce for a signing session. +func (s *Server) MuSig2GetCombinedNonce(_ context.Context, + in *MuSig2GetCombinedNonceRequest) ( + *MuSig2GetCombinedNonceResponse, error) { + + // Check session ID length. + sessionID, err := parseMuSig2SessionID(in.SessionId) + if err != nil { + return nil, fmt.Errorf("error parsing session ID: %w", err) + } + + // Get the combined nonce from the signer. + combinedNonce, err := s.cfg.Signer.MuSig2GetCombinedNonce(sessionID) + if err != nil { + return nil, fmt.Errorf("error getting combined nonce: %w", err) + } + + return &MuSig2GetCombinedNonceResponse{ + CombinedPublicNonce: combinedNonce[:], + }, nil +} + // MuSig2Sign creates a partial signature using the local signing key that was // specified when the session was created. This can only be called when all // public nonces of all participants are known and have been registered with