// pre-define errors for supporting bytom errorFormatter
var (
- ErrDuplicateAlias = errors.New("duplicate account alias")
- ErrFindAccount = errors.New("fail to find account")
- ErrMarshalAccount = errors.New("failed marshal account")
+ ErrDuplicateAlias = errors.New("duplicate account alias")
+ ErrFindAccount = errors.New("fail to find account")
+ ErrMarshalAccount = errors.New("failed marshal account")
+ ErrInvalidAddress = errors.New("invalid address")
+ ErrFindCtrlProgram = errors.New("fail to find account control program")
)
func aliasKey(name string) []byte {
return cps, nil
}
+
+// GetAccountByAddress return account by given address
+func (m *Manager) GetAccountByAddress(address string) (*Account, error) {
+ addr, err := common.DecodeAddress(address, &consensus.ActiveNetParams)
+ if err != nil {
+ return nil, err
+ }
+
+ redeemContract := addr.ScriptAddress()
+ program := []byte{}
+ switch addr.(type) {
+ case *common.AddressWitnessPubKeyHash:
+ program, err = vmutil.P2WPKHProgram(redeemContract)
+ case *common.AddressWitnessScriptHash:
+ program, err = vmutil.P2WSHProgram(redeemContract)
+ default:
+ return nil, ErrInvalidAddress
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ var hash [32]byte
+ cp := CtrlProgram{}
+ sha3pool.Sum256(hash[:], program)
+ rawProgram := m.db.Get(ContractKey(hash))
+ if rawProgram == nil {
+ return nil, ErrFindCtrlProgram
+ }
+
+ if err := json.Unmarshal(rawProgram, &cp); err != nil {
+ return nil, err
+ }
+
+ rawAccount := m.db.Get(Key(cp.AccountID))
+ if rawAccount == nil {
+ return nil, ErrFindAccount
+ }
+
+ account := &Account{}
+ if err := json.Unmarshal(rawAccount, account); err != nil {
+ return nil, err
+ }
+
+ return account, nil
+}
m.Handle("/delete-key", jsonHandler(a.pseudohsmDeleteKey))
m.Handle("/reset-key-password", jsonHandler(a.pseudohsmResetPassword))
+ m.Handle("/sign-message", jsonHandler(a.pseudohsmSignMsg))
+ m.Handle("/verify-message", jsonHandler(a.pseudohsmVerifyMsg))
+
m.Handle("/build-transaction", jsonHandler(a.build))
m.Handle("/sign-transaction", jsonHandler(a.pseudohsmSignTemplates))
m.Handle("/submit-transaction", jsonHandler(a.submit))
import (
"context"
+ "encoding/hex"
log "github.com/sirupsen/logrus"
"github.com/bytom/blockchain/pseudohsm"
"github.com/bytom/blockchain/txbuilder"
+ "github.com/bytom/crypto/ed25519"
"github.com/bytom/crypto/ed25519/chainkd"
+ "github.com/bytom/errors"
"github.com/bytom/net/http/httperror"
)
return a.wallet.Hsm.XSign(xpub, path, data[:], password)
}
+// ResetPasswordResp is response for reset password password
type ResetPasswordResp struct {
Changed bool `json:"changed"`
}
resp.Changed = true
return NewSuccessResponse(resp)
}
+
+// SignMsgResp is response for sign message
+type SignMsgResp struct {
+ Signature string `json:"signature"`
+}
+
+func (a *API) pseudohsmSignMsg(ctx context.Context, ins struct {
+ Address string `json:"address"`
+ Message []byte `json:"message"`
+ Password string `json:"password"`
+}) Response {
+ account, err := a.wallet.AccountMgr.GetAccountByAddress(ins.Address)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ if len(account.XPubs) == 0 {
+ return NewErrorResponse(errors.New("account xpubs is nil"))
+ }
+
+ sig, err := a.wallet.Hsm.XSign(account.XPubs[0], nil, ins.Message, ins.Password)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(SignMsgResp{Signature: hex.EncodeToString(sig)})
+}
+
+// VerifyMsgResp is response for verify message
+type VerifyMsgResp struct {
+ VerifyResult bool `json:" result"`
+}
+
+func (a *API) pseudohsmVerifyMsg(ctx context.Context, ins struct {
+ Address string `json:"address"`
+ Message []byte `json:"message"`
+ Signature []byte `json:"signature"`
+}) Response {
+ account, err := a.wallet.AccountMgr.GetAccountByAddress(ins.Address)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ if len(account.XPubs) == 0 {
+ return NewErrorResponse(errors.New("account xpubs is nil"))
+ }
+
+ if ed25519.Verify(account.XPubs[0].PublicKey(), ins.Message, ins.Signature) {
+ return NewSuccessResponse(VerifyMsgResp{VerifyResult: true})
+ }
+ return NewSuccessResponse(VerifyMsgResp{VerifyResult: false})
+}
BytomcliCmd.AddCommand(deleteKeyCmd)
BytomcliCmd.AddCommand(listKeysCmd)
BytomcliCmd.AddCommand(resetKeyPwdCmd)
+ BytomcliCmd.AddCommand(signMsgCmd)
+ BytomcliCmd.AddCommand(verifyMsgCmd)
BytomcliCmd.AddCommand(createTransactionFeedCmd)
BytomcliCmd.AddCommand(listTransactionFeedsCmd)
deleteKeyCmd.Name(),
listKeysCmd.Name(),
resetKeyPwdCmd.Name(),
+ signMsgCmd.Name(),
+ verifyMsgCmd.Name(),
buildTransactionCmd.Name(),
signTransactionCmd.Name(),
package commands
import (
+ "encoding/hex"
"os"
+
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
jww.FEEDBACK.Println("Successfully reset key password")
},
}
+
+var signMsgCmd = &cobra.Command{
+ Use: "sign-message <address> <message> <password>",
+ Short: "sign message to generate signature",
+ Args: cobra.ExactArgs(3),
+ Run: func(cmd *cobra.Command, args []string) {
+ var req = struct {
+ Address string `json:"address"`
+ Message []byte `json:"message"`
+ Password string `json:"password"`
+ }{Address: args[0], Message: []byte(args[1]), Password: args[2]}
+
+ data, exitCode := util.ClientCall("/sign-message", &req)
+ if exitCode != util.Success {
+ os.Exit(exitCode)
+ }
+ printJSON(data)
+ },
+}
+
+var verifyMsgCmd = &cobra.Command{
+ Use: "verify-message <address> <message> <signature>",
+ Short: "verify signature for specified message",
+ Args: cobra.ExactArgs(3),
+ Run: func(cmd *cobra.Command, args []string) {
+ signature, err := hex.DecodeString(args[2])
+ if err != nil {
+ jww.ERROR.Println("convert signature error:", err)
+ os.Exit(util.ErrLocalExe)
+ }
+
+ var req = struct {
+ Address string `json:"address"`
+ Message []byte `json:"message"`
+ Signature []byte `json:"signature"`
+ }{Address: args[0], Message: []byte(args[1]), Signature: signature}
+
+ data, exitCode := util.ClientCall("/verify-message", &req)
+ if exitCode != util.Success {
+ os.Exit(exitCode)
+ }
+ printJSON(data)
+ },
+}