Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adds unsafeSignEOTS for testing double signing #193

Merged
merged 5 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* [#184](https://github.com/babylonlabs-io/finality-provider/pull/184) eots manager sign record store
* [#189](https://github.com/babylonlabs-io/finality-provider/pull/189) Remove `fpd register-finality-provider` cmd
* [#190](https://github.com/babylonlabs-io/finality-provider/pull/190) Benchmark pub rand
* [#193](https://github.com/babylonlabs-io/finality-provider/pull/193) adds unsafeSignEOTS for e2e tests
* [#195](https://github.com/babylonlabs-io/finality-provider/pull/195) Not block unjailing

### Bug Fixes
Expand Down
19 changes: 19 additions & 0 deletions eotsmanager/client/rpcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@ func (c *EOTSManagerGRpcClient) SignEOTS(uid, chaiID, msg []byte, height uint64,
return &s, nil
}

func (c *EOTSManagerGRpcClient) UnsafeSignEOTS(uid, chaiID, msg []byte, height uint64, passphrase string) (*btcec.ModNScalar, error) {
req := &proto.SignEOTSRequest{
Uid: uid,
ChainId: chaiID,
Msg: msg,
Height: height,
Passphrase: passphrase,
}
res, err := c.client.UnsafeSignEOTS(context.Background(), req)
if err != nil {
return nil, err
}

var s btcec.ModNScalar
s.SetByteSlice(res.Sig)

return &s, nil
}

func (c *EOTSManagerGRpcClient) SignSchnorrSig(uid, msg []byte, passphrase string) (*schnorr.Signature, error) {
req := &proto.SignSchnorrSigRequest{Uid: uid, Msg: msg, Passphrase: passphrase}
res, err := c.client.SignSchnorrSig(context.Background(), req)
Expand Down
8 changes: 7 additions & 1 deletion eotsmanager/eotsmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ type EOTSManager interface {
// SignEOTS signs an EOTS using the private key of the finality provider and the corresponding
// secret randomness of the given chain at the given height
// It fails if the finality provider does not exist or there's no randomness committed to the given height
// or passPhrase is incorrect
// or passPhrase is incorrect. Has built-in anti-slashing mechanism to ensure signature
// for the same height will not be signed twice.
SignEOTS(uid []byte, chainID []byte, msg []byte, height uint64, passphrase string) (*btcec.ModNScalar, error)
Copy link
Member

Choose a reason for hiding this comment

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

We can mention that SignEOTS should have built-in anti-slashing mechanism to ensure signature for the same height will not be signed twice


// UnsafeSignEOTS should only be used in e2e tests for demonstration purposes.
// Does not offer double sign protection.
// Use SignEOTS for real operations.
UnsafeSignEOTS(uid []byte, chainID []byte, msg []byte, height uint64, passphrase string) (*btcec.ModNScalar, error)

// SignSchnorrSig signs a Schnorr signature using the private key of the finality provider
// It fails if the finality provider does not exist or the message size is not 32 bytes
// or passPhrase is incorrect
Expand Down
27 changes: 27 additions & 0 deletions eotsmanager/localmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,14 @@ func (lm *LocalEOTSManager) SignEOTS(fpPk []byte, chainID []byte, msg []byte, he
return &s, nil
}

lm.logger.Error(
"double sign error protection",
zap.String("fp", hex.EncodeToString(fpPk)),
zap.String("msg", hex.EncodeToString(msg)),
zap.Uint64("height", height),
zap.String("chainID", string(chainID)),
)

return nil, eotstypes.ErrDoubleSign
}

Expand Down Expand Up @@ -235,6 +243,25 @@ func (lm *LocalEOTSManager) SignEOTS(fpPk []byte, chainID []byte, msg []byte, he
return signedBytes, nil
}

// UnsafeSignEOTS should only be used in e2e test to demonstrate double sign
func (lm *LocalEOTSManager) UnsafeSignEOTS(fpPk []byte, chainID []byte, msg []byte, height uint64, passphrase string) (*btcec.ModNScalar, error) {
privRand, _, err := lm.getRandomnessPair(fpPk, chainID, height, passphrase)
if err != nil {
return nil, fmt.Errorf("failed to get private randomness: %w", err)
}

privKey, err := lm.getEOTSPrivKey(fpPk, passphrase)
if err != nil {
return nil, fmt.Errorf("failed to get EOTS private key: %w", err)
}

// Update metrics
lm.metrics.IncrementEotsFpTotalEotsSignCounter(hex.EncodeToString(fpPk))
lm.metrics.SetEotsFpLastEotsSignHeight(hex.EncodeToString(fpPk), float64(height))

return eots.Sign(privKey, privRand, msg)
}

func (lm *LocalEOTSManager) SignSchnorrSig(fpPk []byte, msg []byte, passphrase string) (*schnorr.Signature, error) {
privKey, err := lm.getEOTSPrivKey(fpPk, passphrase)
if err != nil {
Expand Down
46 changes: 26 additions & 20 deletions eotsmanager/proto/eotsmanager.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions eotsmanager/proto/eotsmanager.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ service EOTSManager {
rpc SignEOTS (SignEOTSRequest)
returns (SignEOTSResponse);

// UnsafeSignEOTS used only for testing purpose. Use SignEOTS for real operations
rpc UnsafeSignEOTS (SignEOTSRequest)
returns (SignEOTSResponse);

// SignSchnorrSig signs a Schnorr sig with the EOTS private key
rpc SignSchnorrSig (SignSchnorrSigRequest)
returns (SignSchnorrSigResponse);
Expand Down
39 changes: 39 additions & 0 deletions eotsmanager/proto/eotsmanager_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions eotsmanager/service/rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ func (r *rpcServer) SignEOTS(_ context.Context, req *proto.SignEOTSRequest) (
return &proto.SignEOTSResponse{Sig: sigBytes[:]}, nil
}

// UnsafeSignEOTS only used for testing purposes. Doesn't offer slashing protection!
func (r *rpcServer) UnsafeSignEOTS(_ context.Context, req *proto.SignEOTSRequest) (
*proto.SignEOTSResponse, error) {
sig, err := r.em.UnsafeSignEOTS(req.Uid, req.ChainId, req.Msg, req.Height, req.Passphrase)
if err != nil {
return nil, err
}

sigBytes := sig.Bytes()

return &proto.SignEOTSResponse{Sig: sigBytes[:]}, nil
}

// SignSchnorrSig signs a Schnorr sig with the EOTS private key
func (r *rpcServer) SignSchnorrSig(_ context.Context, req *proto.SignSchnorrSigRequest) (
*proto.SignSchnorrSigResponse, error) {
Expand Down
9 changes: 8 additions & 1 deletion finality-provider/cmd/fpd/daemon/daemon_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ func CommandAddFinalitySig() *cobra.Command {
}
cmd.Flags().String(fpdDaemonAddressFlag, defaultFpdDaemonAddress, "The RPC server address of fpd")
cmd.Flags().String(appHashFlag, defaultAppHashStr, "The last commit hash of the chain block")
cmd.Flags().Bool(checkDoubleSignFlag, true, "If 'true', uses anti-slashing protection when doing EOTS sign")

return cmd
}

Expand All @@ -383,6 +385,11 @@ func runCommandAddFinalitySig(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to read flag %s: %w", appHashFlag, err)
}

checkDoubleSign, err := flags.GetBool(checkDoubleSignFlag)
if err != nil {
return fmt.Errorf("failed to read flag %s: %w", checkDoubleSignFlag, err)
}

client, cleanUp, err := dc.NewFinalityProviderServiceGRpcClient(daemonAddress)
if err != nil {
return err
Expand All @@ -398,7 +405,7 @@ func runCommandAddFinalitySig(cmd *cobra.Command, args []string) error {
return err
}

res, err := client.AddFinalitySignature(context.Background(), fpPk.MarshalHex(), blkHeight, appHash)
res, err := client.AddFinalitySignature(context.Background(), fpPk.MarshalHex(), blkHeight, appHash, checkDoubleSign)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions finality-provider/cmd/fpd/daemon/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
hdPathFlag = "hd-path"
chainIDFlag = "chain-id"
signedFlag = "signed"
checkDoubleSignFlag = "check-double-sign"

// flags for description
monikerFlag = "moniker"
Expand Down
Loading
Loading