Skip to content

Commit

Permalink
Merge pull request #35 from piavgh/feature/verify-zklogin-signature
Browse files Browse the repository at this point in the history
feat: verify zklogin signature
  • Loading branch information
JaydenLink authored Oct 7, 2024
2 parents 3017a0d + 47fbb54 commit 94d2e46
Show file tree
Hide file tree
Showing 14 changed files with 673 additions and 2 deletions.
33 changes: 33 additions & 0 deletions cryptography/scheme/signature_scheme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package scheme

type SignatureScheme string

const (
ED25519 SignatureScheme = "ED25519"
Secp256k1 SignatureScheme = "Secp256k1"
Secp256r1 SignatureScheme = "Secp256r1"
MultiSig SignatureScheme = "MultiSig"
ZkLogin SignatureScheme = "ZkLogin"
)

var SignatureSchemeToSize = map[SignatureScheme]int{
ED25519: 32,
Secp256k1: 33,
Secp256r1: 33,
}

var SignatureSchemeToFlag = map[SignatureScheme]byte{
ED25519: 0x00,
Secp256k1: 0x01,
Secp256r1: 0x02,
MultiSig: 0x03,
ZkLogin: 0x05,
}

var SignatureFlagToScheme = map[byte]SignatureScheme{
0x00: ED25519,
0x01: Secp256k1,
0x02: Secp256r1,
0x03: MultiSig,
0x05: ZkLogin,
}
68 changes: 68 additions & 0 deletions cryptography/signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package cryptography

import (
"fmt"
"strings"

"github.com/block-vision/sui-go-sdk/cryptography/scheme"
"github.com/block-vision/sui-go-sdk/mystenbcs"
"github.com/block-vision/sui-go-sdk/zklogin"
)

type SignaturePubkeyPair struct {
SignatureScheme scheme.SignatureScheme
Signature []byte
PubKey []byte
}

func parseSerializedSignature(serializedSignature string) (*SignaturePubkeyPair, error) {
if strings.EqualFold(serializedSignature, "") {
return nil, fmt.Errorf("multiSig is not supported")
}

bytes, err := mystenbcs.FromBase64(serializedSignature)
if err != nil {
return nil, err
}

signatureScheme, ok := scheme.SignatureFlagToScheme[bytes[0]]
if !ok {
return nil, fmt.Errorf("signature flag is not supported")
}

switch signatureScheme {
case "ZkLogin":
parsedSerializedZkLoginSignature, err := zklogin.ParseSerializedZkLoginSignature(serializedSignature)
if err != nil {
return nil, err
}

return &SignaturePubkeyPair{
SignatureScheme: parsedSerializedZkLoginSignature.SignatureScheme,
Signature: parsedSerializedZkLoginSignature.Signature,
PubKey: parsedSerializedZkLoginSignature.PubKey,
}, nil
case "ED25519":
fallthrough
case "Secp256k1":
fallthrough
case "Secp256r1":
size, ok := scheme.SignatureSchemeToSize[signatureScheme]
if !ok {
return nil, fmt.Errorf("signature scheme is not supported")
}

signature := bytes[1 : len(bytes)-size]
pubKeyBytes := bytes[1+len(signature):]

keyPair := &SignaturePubkeyPair{
SignatureScheme: signatureScheme,
Signature: signature,
PubKey: pubKeyBytes,
}

return keyPair, nil
default:
return nil, fmt.Errorf("signature scheme is not supported")
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ require (
)

require (
github.com/fardream/go-bcs v0.7.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/leodido/go-urn v1.2.2 // indirect
github.com/machinebox/graphql v0.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/sys v0.20.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fardream/go-bcs v0.7.0 h1:4YIiCXrtUFiRT86TsvUx+tIennZBRXQCzrgt8xC2g0c=
github.com/fardream/go-bcs v0.7.0/go.mod h1:UsoxhIoe2GsVexX0s5NDLIChxeb/JUbjw7IWzzgF3Xk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
Expand Down
60 changes: 60 additions & 0 deletions keypairs/ed25519/publickey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package ed25519

import (
"crypto/ed25519"
"encoding/base64"
"encoding/hex"
"fmt"

"github.com/machinebox/graphql"
"golang.org/x/crypto/blake2b"

"github.com/block-vision/sui-go-sdk/constant"
)

type Ed25519PublicKey struct {
signature []byte
}

func NewEd25519PublicKey(signature []byte) *Ed25519PublicKey {
return &Ed25519PublicKey{
signature: signature,
}
}

func (e *Ed25519PublicKey) ToSuiAddress() string {
return ""
}

func (e *Ed25519PublicKey) VerifyPersonalMessage(message []byte, signature []byte, client *graphql.Client) (bool, error) {
b64Message := base64.StdEncoding.EncodeToString([]byte(message))
return VerifyMessage(b64Message, signature, constant.PersonalMessageIntentScope)
}

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])
}
6 changes: 4 additions & 2 deletions models/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"log"
"strings"

"github.com/block-vision/sui-go-sdk/constant"

"golang.org/x/crypto/blake2b"

"github.com/block-vision/sui-go-sdk/constant"
)

type InputObjectKind map[string]interface{}
Expand Down Expand Up @@ -176,6 +176,8 @@ func parseSignatureScheme(scheme byte) string {
return "Secp256r1"
case 3:
return "MultiSig"
case 5:
return "ZkLogin"
default:
return "ED25519"
}
Expand Down
16 changes: 16 additions & 0 deletions mystenbcs/b64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mystenbcs

import "encoding/base64"

func FromBase64(base64String string) ([]byte, error) {
bytes, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
return nil, err
}

return bytes, nil
}

func ToBase64(bytes []byte) string {
return base64.StdEncoding.EncodeToString(bytes)
}
8 changes: 8 additions & 0 deletions verify/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package verify

import "github.com/machinebox/graphql"

type IPublicKey interface {
ToSuiAddress() string
VerifyPersonalMessage(message []byte, signature []byte, client *graphql.Client) (bool, error)
}
45 changes: 45 additions & 0 deletions verify/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package verify

import (
"errors"
"fmt"

"github.com/block-vision/sui-go-sdk/cryptography"
"github.com/block-vision/sui-go-sdk/cryptography/scheme"
"github.com/block-vision/sui-go-sdk/keypairs/ed25519"
"github.com/block-vision/sui-go-sdk/zklogin"
)

func VerifyPersonalMessageSignature(message []byte, signature []byte, options *zklogin.ZkLoginPublicIdentifierOptions) (signer string, pass bool, err error) {
parsedSignature := parseSignature(signature, options)

publicKey, err := publicKeyFromRawBytes(parsedSignature.SignatureScheme, parsedSignature.PubKey, options)
if err != nil {
return "", false, err
}

pass, err = publicKey.VerifyPersonalMessage(message, parsedSignature.Signature, options.Client)
if err != nil {
return "", false, err
}

address := publicKey.ToSuiAddress()

return address, true, nil
}

func parseSignature(signature []byte, options *zklogin.ZkLoginPublicIdentifierOptions) *cryptography.SignaturePubkeyPair {
return nil
}

// publicKeyFromRawBytes function in Go
func publicKeyFromRawBytes(signatureScheme scheme.SignatureScheme, bytes []byte, options *zklogin.ZkLoginPublicIdentifierOptions) (IPublicKey, error) {
switch signatureScheme {
case scheme.ED25519:
return ed25519.NewEd25519PublicKey(bytes), nil
case scheme.ZkLogin:
return zklogin.NewZkLoginPublicIdentifier(bytes, options), nil
default:
return nil, errors.New(fmt.Sprintf("Unsupported signature scheme %s", signatureScheme))
}
}
27 changes: 27 additions & 0 deletions zklogin/bcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package zklogin

type ProofPoints struct {
A []string `bcs:"a"`
B [][]string `bcs:"b"`
C []string `bcs:"c"`
}

type IssBase64Details struct {
Value string `bcs:"value"`
IndexMod4 uint8 `bcs:"indexMod4"`
}

type ZkLoginSignatureInputs struct {
ProofPoints ProofPoints `bcs:"proofPoints"`
IssBase64Details IssBase64Details `bcs:"issBase64Details"`
HeaderBase64 string `bcs:"headerBase64"`
AddressSeed string `bcs:"addressSeed"`
}

type ZkLoginSignature struct {
Inputs ZkLoginSignatureInputs `bcs:"inputs"`
MaxEpoch uint64 `bcs:"maxEpoch"`
UserSignature []byte `bcs:"userSignature"`
Iss string `bcs:"iss"`
AddressSeed string `bcs:"addressSeed"`
}
Loading

0 comments on commit 94d2e46

Please sign in to comment.