--- /dev/null
+package api
+
+import (
+ "context"
+ "encoding/hex"
+ "strings"
+
+ "github.com/vapor/blockchain/signers"
+ "github.com/vapor/common"
+ "github.com/vapor/consensus"
+ "github.com/vapor/crypto"
+ "github.com/vapor/crypto/ed25519"
+ "github.com/vapor/crypto/ed25519/chainkd"
+ chainjson "github.com/vapor/encoding/json"
+)
+
+// SignMsgResp is response for sign message
+type SignMsgResp struct {
+ Signature string `json:"signature"`
+ DerivedXPub chainkd.XPub `json:"derived_xpub"`
+}
+
+func (a *API) signMessage(ctx context.Context, ins struct {
+ Address string `json:"address"`
+ Message chainjson.HexBytes `json:"message"`
+ Password string `json:"password"`
+}) Response {
+ cp, err := a.wallet.AccountMgr.GetLocalCtrlProgramByAddress(ins.Address)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ account, err := a.wallet.AccountMgr.GetAccountByProgram(cp)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ path, err := signers.Path(account.Signer, signers.AccountKeySpace, cp.Change, cp.KeyIndex)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path)
+
+ sig, err := a.wallet.Hsm.XSign(account.XPubs[0], path, ins.Message, ins.Password)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(SignMsgResp{
+ Signature: hex.EncodeToString(sig),
+ DerivedXPub: derivedXPubs[0],
+ })
+}
+
+// VerifyMsgResp is response for verify message
+type VerifyMsgResp struct {
+ VerifyResult bool `json:"result"`
+}
+
+func (a *API) verifyMessage(ctx context.Context, ins struct {
+ Address string `json:"address"`
+ DerivedXPub chainkd.XPub `json:"derived_xpub"`
+ Message chainjson.HexBytes `json:"message"`
+ Signature string `json:"signature"`
+}) Response {
+ sig, err := hex.DecodeString(ins.Signature)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ derivedPK := ins.DerivedXPub.PublicKey()
+ pubHash := crypto.Ripemd160(derivedPK)
+ addressPubHash, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ address := addressPubHash.EncodeAddress()
+ if address != strings.TrimSpace(ins.Address) {
+ return NewSuccessResponse(VerifyMsgResp{VerifyResult: false})
+ }
+
+ if ed25519.Verify(ins.DerivedXPub.PublicKey(), ins.Message, sig) {
+ return NewSuccessResponse(VerifyMsgResp{VerifyResult: true})
+ }
+ return NewSuccessResponse(VerifyMsgResp{VerifyResult: false})
+}