Merge pull request #14 from wuuuk/feat-verify-message
feat: verify message and verify transaction
This commit is contained in:
10
constant/intent.go
Normal file
10
constant/intent.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package constant
|
||||
|
||||
type IntentScope = uint8
|
||||
|
||||
const (
|
||||
TransactionDataIntentScope IntentScope = 0
|
||||
TransactionEffectsIntentScope IntentScope = 1
|
||||
CheckpointSummaryIntentScope IntentScope = 2
|
||||
PersonalMessageIntentScope IntentScope = 3
|
||||
)
|
||||
27
models/intent.go
Normal file
27
models/intent.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import "github.com/block-vision/sui-go-sdk/constant"
|
||||
|
||||
type AppId int
|
||||
|
||||
const (
|
||||
Sui AppId = 0
|
||||
)
|
||||
|
||||
type IntentVersion int
|
||||
|
||||
const (
|
||||
V0 IntentVersion = 0
|
||||
)
|
||||
|
||||
func IntentWithScope(intentScope constant.IntentScope) []int {
|
||||
return []int{int(intentScope), int(V0), int(Sui)}
|
||||
}
|
||||
|
||||
func NewMessageWithIntent(message []byte, scope constant.IntentScope) []byte {
|
||||
intent := []byte{scope, 0, 0}
|
||||
intentMessage := make([]byte, len(intent)+len(message))
|
||||
copy(intentMessage, intent)
|
||||
copy(intentMessage[len(intent):], message)
|
||||
return intentMessage
|
||||
}
|
||||
@@ -5,9 +5,13 @@ import (
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/block-vision/sui-go-sdk/constant"
|
||||
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
|
||||
type InputObjectKind map[string]interface{}
|
||||
@@ -38,6 +42,12 @@ type HexData struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
type SignaturePubkeyPair struct {
|
||||
SignatureScheme string
|
||||
Signature []byte
|
||||
PubKey []byte
|
||||
}
|
||||
|
||||
func NewHexData(str string) (*HexData, error) {
|
||||
if strings.HasPrefix(str, "0x") || strings.HasPrefix(str, "0X") {
|
||||
str = str[2:]
|
||||
@@ -113,7 +123,7 @@ func (txn *TxnMetaData) SignSerializedSigWith(privateKey ed25519.PrivateKey) *Si
|
||||
}
|
||||
return &SignedTransactionSerializedSig{
|
||||
TxBytes: txn.TxBytes,
|
||||
Signature: toSerializedSignature(sigBytes, privateKey.Public().(ed25519.PublicKey)),
|
||||
Signature: ToSerializedSignature(sigBytes, privateKey.Public().(ed25519.PublicKey)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +135,7 @@ func messageWithIntent(message []byte) []byte {
|
||||
return intentMessage
|
||||
}
|
||||
|
||||
func toSerializedSignature(signature, pubKey []byte) string {
|
||||
func ToSerializedSignature(signature, pubKey []byte) string {
|
||||
signatureLen := len(signature)
|
||||
pubKeyLen := len(pubKey)
|
||||
serializedSignature := make([]byte, 1+signatureLen+pubKeyLen)
|
||||
@@ -134,3 +144,76 @@ func toSerializedSignature(signature, pubKey []byte) string {
|
||||
copy(serializedSignature[1+signatureLen:], pubKey)
|
||||
return base64.StdEncoding.EncodeToString(serializedSignature)
|
||||
}
|
||||
|
||||
func FromSerializedSignature(serializedSignature string) (*SignaturePubkeyPair, error) {
|
||||
_bytes, err := base64.StdEncoding.DecodeString(serializedSignature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signatureScheme := parseSignatureScheme(_bytes[0])
|
||||
if strings.EqualFold(serializedSignature, "") {
|
||||
return nil, fmt.Errorf("multiSig is not supported")
|
||||
}
|
||||
|
||||
signature := _bytes[1 : len(_bytes)-32]
|
||||
pubKeyBytes := _bytes[1+len(signature):]
|
||||
|
||||
keyPair := &SignaturePubkeyPair{
|
||||
SignatureScheme: signatureScheme,
|
||||
Signature: signature,
|
||||
PubKey: pubKeyBytes,
|
||||
}
|
||||
return keyPair, nil
|
||||
}
|
||||
|
||||
func parseSignatureScheme(scheme byte) string {
|
||||
switch scheme {
|
||||
case 0:
|
||||
return "ED25519"
|
||||
case 1:
|
||||
return "Secp256k1"
|
||||
case 2:
|
||||
return "Secp256r1"
|
||||
case 3:
|
||||
return "MultiSig"
|
||||
default:
|
||||
return "ED25519"
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyPersonalMessage(message string, signature string) (signer string, pass bool, err error) {
|
||||
b64Message := base64.StdEncoding.EncodeToString([]byte(message))
|
||||
return VerifyMessage(b64Message, signature, constant.PersonalMessageIntentScope)
|
||||
}
|
||||
|
||||
func VerifyTransaction(b64Message string, signature string) (signer string, pass bool, err error) {
|
||||
return VerifyMessage(b64Message, signature, constant.TransactionDataIntentScope)
|
||||
}
|
||||
|
||||
func VerifyMessage(message, signature string, scope constant.IntentScope) (signer string, pass bool, err error) {
|
||||
b64Bytes, _ := base64.StdEncoding.DecodeString(message)
|
||||
messageBytes := NewMessageWithIntent(b64Bytes, scope)
|
||||
|
||||
serializedSignature, err := FromSerializedSignature(signature)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
digest := blake2b.Sum256(messageBytes)
|
||||
|
||||
pass = ed25519.Verify(serializedSignature.PubKey[:], digest[:], serializedSignature.Signature)
|
||||
|
||||
signer = Ed25519PublicKeyToSuiAddress(serializedSignature.PubKey)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("invalid signer %v", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Ed25519PublicKeyToSuiAddress(pubKey []byte) string {
|
||||
newPubkey := []byte{byte(SigFlagEd25519)}
|
||||
newPubkey = append(newPubkey, pubKey...)
|
||||
|
||||
addrBytes := blake2b.Sum256(newPubkey)
|
||||
return fmt.Sprintf("0x%s", hex.EncodeToString(addrBytes[:])[:64])
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package signer
|
||||
|
||||
type AppId int
|
||||
|
||||
const (
|
||||
Sui AppId = 0
|
||||
)
|
||||
|
||||
type IntentVersion int
|
||||
|
||||
const (
|
||||
V0 IntentVersion = 0
|
||||
)
|
||||
|
||||
type IntentScope int
|
||||
|
||||
const (
|
||||
TransactionData IntentScope = 0
|
||||
TransactionEffects IntentScope = 1
|
||||
CheckpointSummary IntentScope = 2
|
||||
PersonalMessage IntentScope = 3
|
||||
)
|
||||
|
||||
func IntentWithScope(intentScope IntentScope) []int {
|
||||
return []int{int(intentScope), int(V0), int(Sui)}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package signer
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/block-vision/sui-go-sdk/common/keypair"
|
||||
"github.com/block-vision/sui-go-sdk/constant"
|
||||
"github.com/block-vision/sui-go-sdk/models"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
@@ -49,3 +54,42 @@ func NewSignertWithMnemonic(mnemonic string) (*Signer, error) {
|
||||
}
|
||||
return NewSigner(key.Key), nil
|
||||
}
|
||||
|
||||
type SignedMessageSerializedSig struct {
|
||||
Message string `json:"message"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
func (s *Signer) SignMessage(data string, scope constant.IntentScope) (*SignedMessageSerializedSig, error) {
|
||||
txBytes, _ := base64.StdEncoding.DecodeString(data)
|
||||
message := models.NewMessageWithIntent(txBytes, scope)
|
||||
digest := blake2b.Sum256(message)
|
||||
var noHash crypto.Hash
|
||||
sigBytes, err := s.PriKey.Sign(nil, digest[:], noHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &SignedMessageSerializedSig{
|
||||
Message: data,
|
||||
Signature: models.ToSerializedSignature(sigBytes, s.PriKey.Public().(ed25519.PublicKey)),
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *Signer) SignTransaction(b64TxBytes string) (*models.SignedTransactionSerializedSig, error) {
|
||||
result, err := s.SignMessage(b64TxBytes, constant.PersonalMessageIntentScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.SignedTransactionSerializedSig{
|
||||
TxBytes: result.Message,
|
||||
Signature: result.Signature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Signer) SignPersonalMessage(message string) (*SignedMessageSerializedSig, error) {
|
||||
b64Message := base64.StdEncoding.EncodeToString([]byte(message))
|
||||
return s.SignMessage(b64Message, constant.PersonalMessageIntentScope)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user