Skip to content

Commit

Permalink
Re: #1290: Add a lotus wallet verify API and CLI command
Browse files Browse the repository at this point in the history
- The command takes an address, message, and signature, and returns true if the sig is valid
  • Loading branch information
arajasek committed Feb 27, 2020
1 parent 5be1c08 commit 37b3ce8
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 1 deletion.
1 change: 1 addition & 0 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type FullNode interface {
WalletBalance(context.Context, address.Address) (types.BigInt, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error)
WalletVerify(context.Context, address.Address, []byte, *types.Signature) bool
WalletDefaultAddress(context.Context) (address.Address, error)
WalletSetDefault(context.Context, address.Address) error
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
Expand Down
5 changes: 5 additions & 0 deletions api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type FullNodeStruct struct {
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"`
WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
WalletVerify func(context.Context, address.Address, []byte, *types.Signature) bool `perm:"read"`
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
Expand Down Expand Up @@ -311,6 +312,10 @@ func (c *FullNodeStruct) WalletSignMessage(ctx context.Context, k address.Addres
return c.Internal.WalletSignMessage(ctx, k, msg)
}

func (c *FullNodeStruct) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *types.Signature) bool {
return c.Internal.WalletVerify(ctx, k, msg, sig)
}

func (c *FullNodeStruct) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
return c.Internal.WalletDefaultAddress(ctx)
}
Expand Down
14 changes: 14 additions & 0 deletions cli/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ const (
metadataTraceConetxt = "traceContext"
)

// custom CLI error

type ErrCmdFailed struct {
msg string
}

func (e *ErrCmdFailed) Error() string {
return e.msg
}

func NewCliError(s string) error {
return &ErrCmdFailed{s}
}

// ApiConnector returns API instance
type ApiConnector func() api.FullNode

Expand Down
51 changes: 51 additions & 0 deletions cli/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var walletCmd = &cli.Command{
walletGetDefault,
walletSetDefault,
walletSign,
walletVerify,
},
}

Expand Down Expand Up @@ -288,3 +289,53 @@ var walletSign = &cli.Command{
return nil
},
}

var walletVerify = &cli.Command{
Name: "verify",
Usage: "verify the signature of a message",
ArgsUsage: "<signing address> <hexMessage> <signature>",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)

if !cctx.Args().Present() || cctx.NArg() != 3 {
return fmt.Errorf("must specify signing address, mnessage, and signature to verify")
}

addr, err := address.NewFromString(cctx.Args().First())

if err != nil {
return err
}

msg, err := hex.DecodeString(cctx.Args().Get(1))

if err != nil {
return err
}

sigBytes, err := hex.DecodeString(cctx.Args().Get(2))

if err != nil {
return err
}

sig, err := types.SignatureFromBytes(sigBytes)

if err != nil {
return err
}

if api.WalletVerify(ctx, addr, msg, &sig) {
fmt.Println("valid")
return nil
} else {
fmt.Println("invalid")
return NewCliError("CLI Verify called with invalid signature")
}
},
}
7 changes: 6 additions & 1 deletion cmd/lotus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ func main() {
Code: trace.StatusCodeFailedPrecondition,
Message: err.Error(),
})
log.Warnf("%+v", err)
_, ok := err.(*lcli.ErrCmdFailed)
if ok {
log.Debugf("%+v", err)
} else {
log.Warnf("%+v", err)
}
os.Exit(1)
}
}
5 changes: 5 additions & 0 deletions node/impl/full/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package full

import (
"context"
"github.com/filecoin-project/lotus/lib/sigs"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/stmgr"
Expand Down Expand Up @@ -53,6 +54,10 @@ func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, ms
}, nil
}

func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *types.Signature) bool {
return sigs.Verify(sig, k, msg) == nil
}

func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
return a.Wallet.GetDefault()
}
Expand Down

0 comments on commit 37b3ce8

Please sign in to comment.