Skip to content

Commit

Permalink
refactored crypto, addresses, and the engines auth to be better plugg…
Browse files Browse the repository at this point in the history
…able with custom / new auth (#335)

* refactored crypto, addresses, and the engines auth to be better pluggable with custom / new auth

* added gavins changes

* changed public key logging from base64 to hex

* better abstracted away the authenticators, as suggested by Jon

* added jons changed
  • Loading branch information
brennanjl committed Feb 26, 2024
1 parent 55cb29f commit cbd615d
Show file tree
Hide file tree
Showing 65 changed files with 868 additions and 1,829 deletions.
6 changes: 4 additions & 2 deletions cmd/kwil-admin/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"

"github.com/kwilteam/kwil-db/cmd/internal/display"
"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/client"
"github.com/kwilteam/kwil-db/pkg/crypto"
)
Expand Down Expand Up @@ -87,8 +88,9 @@ func edSigningClient(rpcAddr string, privKey []byte) (*client.Client, error) {
return nil, err
}

signer := crypto.NewStdEd25519Signer(edPrivKey)
options := []client.Option{client.WithSigner(signer), client.WithTLSCert("")}
signer := auth.Ed25519Signer{Ed25519PrivateKey: *edPrivKey}

options := []client.Option{client.WithSigner(&signer), client.WithTLSCert("")}
return client.Dial(rpcAddr, options...)
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/kwil-cli/cmds/common/roundtripper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"fmt"

"github.com/kwilteam/kwil-db/cmd/kwil-cli/config"
"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/client"
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/kwilteam/kwil-db/pkg/log"
)

Expand Down Expand Up @@ -37,8 +37,8 @@ func DialClient(ctx context.Context, flags uint8, fn RoundTripper) error {
return fmt.Errorf("private key not provided")
}

signer := crypto.DefaultSigner(conf.PrivateKey)
options = append(options, client.WithSigner(signer))
signer := auth.EthPersonalSigner{Secp256k1PrivateKey: *conf.PrivateKey}
options = append(options, client.WithSigner(&signer))
}

if conf.GrpcURL == "" {
Expand Down
5 changes: 3 additions & 2 deletions cmd/kwil-cli/cmds/utils/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/kwilteam/kwil-db/cmd/internal/display"
"github.com/kwilteam/kwil-db/cmd/kwil-cli/config"
"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/client/types"
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/kwilteam/kwil-db/pkg/transactions"
Expand Down Expand Up @@ -56,9 +57,9 @@ func Example_respStr_json_withError() {
func getExampleTxQueryResponse() *types.TcTxQueryResponse {
secp256k1EpSigHex := "cb3fed7f6ff36e59054c04a831b215e514052753ee353e6fe31d4b4ef736acd6155127db555d3006ba14fcb4c79bbad56c8e63b81a9896319bb053a9e253475800"
secp256k1EpSigBytes, _ := hex.DecodeString(secp256k1EpSigHex)
secpSig := crypto.Signature{
secpSig := auth.Signature{
Signature: secp256k1EpSigBytes,
Type: crypto.SignatureTypeSecp256k1Personal,
Type: auth.EthAuth,
}

rawPayload := transactions.ActionExecution{
Expand Down
2 changes: 1 addition & 1 deletion cmd/kwil-cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

type KwilCliConfig struct {
PrivateKey crypto.PrivateKey
PrivateKey *crypto.Secp256k1PrivateKey
GrpcURL string
TLSCertFile string
}
Expand Down
2 changes: 2 additions & 0 deletions internal/app/kwild/server/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/kwilteam/kwil-db/internal/pkg/transport"
"github.com/kwilteam/kwil-db/pkg/abci"
"github.com/kwilteam/kwil-db/pkg/abci/cometbft"
"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/balances"
"github.com/kwilteam/kwil-db/pkg/engine"
"github.com/kwilteam/kwil-db/pkg/grpc/gateway"
Expand Down Expand Up @@ -212,6 +213,7 @@ func buildEngine(d *coreDependencies, a *sessions.AtomicCommitter) *engine.Engin

e, err := engine.Open(d.ctx, d.opener,
sqlCommitRegister,
auth.GetAddress,
engine.WithLogger(*d.log.Named("engine")),
engine.WithExtensions(adaptExtensions(extensions)),
)
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/grpc/txsvc/v1/broadcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (s *Service) Broadcast(ctx context.Context, req *txpb.BroadcastRequest) (*t
return nil, status.Errorf(codes.Internal, "failed to convert transaction")
}

logger = logger.With(zap.String("from", tx.GetSenderAddress()))
logger = logger.With(zap.String("from", hex.EncodeToString(tx.Sender)))

err = tx.Verify()
if err != nil {
Expand Down
14 changes: 2 additions & 12 deletions internal/controller/grpc/txsvc/v1/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"

txpb "github.com/kwilteam/kwil-db/api/protobuf/tx/v1"
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/kwilteam/kwil-db/pkg/grpc/client/v1/conversion"
"github.com/kwilteam/kwil-db/pkg/transactions"
"google.golang.org/grpc/codes"
Expand All @@ -18,7 +17,7 @@ func (s *Service) Call(ctx context.Context, req *txpb.CallRequest) (*txpb.CallRe
return nil, status.Errorf(codes.InvalidArgument, "failed to convert action call: %s", err.Error())
}

if msg.GetSender() != nil {
if msg.Sender != nil {
err = msg.Verify()
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to verify signed message: %s", err.Error())
Expand Down Expand Up @@ -66,22 +65,13 @@ func convertActionCall(req *txpb.CallRequest) (*transactions.ActionCall, *transa
return nil, nil, err
}

// NOTE: here we infer the public key type from the signature type
var sender crypto.PublicKey
if req.Sender != nil {
sender, err = crypto.PublicKeyFromBytes(convSignature.KeyType(), req.Sender)
if err != nil {
return nil, nil, err
}
}

return &actionPayload, &transactions.CallMessage{
Body: &transactions.CallMessageBody{
Description: req.Body.Description,
Payload: req.Body.Payload,
},
Signature: convSignature,
Sender: sender,
Sender: req.Sender,
Serialization: transactions.SignedMsgSerializationType(req.Serialization),
}, nil
}
4 changes: 2 additions & 2 deletions internal/controller/grpc/txsvc/v1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/kwilteam/kwil-db/pkg/balances"
engineTypes "github.com/kwilteam/kwil-db/pkg/engine/types"
"github.com/kwilteam/kwil-db/pkg/log"
"github.com/kwilteam/kwil-db/pkg/modules/datasets"
"github.com/kwilteam/kwil-db/pkg/transactions"
"github.com/kwilteam/kwil-db/pkg/validators"
)

Expand Down Expand Up @@ -43,7 +43,7 @@ func NewService(engine EngineReader, accountStore AccountReader, vstore Validato
}

type EngineReader interface {
Call(ctx context.Context, dbid string, action string, args []any, msg datasets.DatasetMessage) ([]map[string]any, error)
Call(ctx context.Context, dbid string, action string, args []any, msg *transactions.CallMessage) ([]map[string]any, error)
GetSchema(ctx context.Context, dbid string) (*engineTypes.Schema, error)
ListOwnedDatabases(ctx context.Context, owner []byte) ([]string, error)
PriceDeploy(ctx context.Context, schema *engineTypes.Schema) (price *big.Int, err error)
Expand Down
6 changes: 3 additions & 3 deletions pkg/abci/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (a *AbciApp) CheckTx(incoming abciTypes.RequestCheckTx) abciTypes.ResponseC
}

logger.Debug("",
zap.String("sender", tx.GetSenderAddress()),
zap.String("sender", hex.EncodeToString(tx.Sender)),
zap.String("PayloadType", tx.Body.PayloadType.String()))

err = tx.Verify()
Expand Down Expand Up @@ -212,7 +212,7 @@ func (a *AbciApp) DeliverTx(req abciTypes.RequestDeliverTx) abciTypes.ResponseDe
gasUsed := int64(0)
txCode := CodeOk

logger = logger.With(zap.String("Sender", tx.GetSenderAddress()),
logger = logger.With(zap.String("sender", hex.EncodeToString(tx.Sender)),
zap.String("PayloadType", tx.Body.PayloadType.String()))

switch tx.Body.PayloadType {
Expand Down Expand Up @@ -244,7 +244,7 @@ func (a *AbciApp) DeliverTx(req abciTypes.RequestDeliverTx) abciTypes.ResponseDe
{
Type: transactions.PayloadTypeDeploySchema.String(),
Attributes: []abciTypes.EventAttribute{
{Key: "Sender", Value: tx.GetSenderAddress(), Index: true},
{Key: "sender", Value: hex.EncodeToString(tx.Sender), Index: true},
{Key: "Result", Value: "Success", Index: true},
{Key: "DBID", Value: dbID, Index: true},
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/abci/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func PrintPrivKeyInfo(privateKey []byte) {
pub := priv.PubKey().(ed25519.PubKey)
nodeID := p2p.PubKeyToID(pub)

fmt.Printf("Private key (hex): %x\n", priv.Bytes())
fmt.Printf("Private key (hex): %s\n", hex.EncodeToString(priv.Bytes()))
fmt.Printf("Private key (base64): %s\n",
base64.StdEncoding.EncodeToString(priv.Bytes())) // "value" in abci/config/node_key.json
fmt.Printf("Public key (base64): %s\n",
Expand Down
4 changes: 2 additions & 2 deletions pkg/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"context"

"github.com/kwilteam/kwil-db/pkg/admin/types"
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/kwilteam/kwil-db/pkg/auth"
admClient "github.com/kwilteam/kwil-db/pkg/grpc/client/admin/v0"
"github.com/kwilteam/kwil-db/pkg/log"

Expand All @@ -17,7 +17,7 @@ import (
// service on a running kwild node.
type Client struct {
client *admClient.AdminClient
signer crypto.Signer // for use in methods that require signing a transaction with a Kwil account
signer auth.Signer // for use in methods that require signing a transaction with a Kwil account
logger log.Logger
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/admin/opts.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package admin

import (
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/log"
)

Expand All @@ -13,7 +13,7 @@ func WithLogger(logger log.Logger) ClientOpt {
}
}

func WithSigner(signer crypto.Signer) ClientOpt {
func WithSigner(signer auth.Signer) ClientOpt {
return func(c *Client) {
c.signer = signer
}
Expand Down
63 changes: 63 additions & 0 deletions pkg/auth/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Package auth provides an interface for developers to implement their own Kwil authentication drivers.
Similar to Go's database/sql package, developers can implement the `Authenticator` interface and register it with the `RegisterAuthenticator` function.
*/
package auth

import (
"errors"
"fmt"
"strings"
)

// Authenticator is an interface for authenticating an incoming call
// It is made to work with keypair authentication
type Authenticator interface {
// Verify verifies the signature against the given public key and data.
Verify(sender, msg, signature []byte) error

// Address returns an address from a public key
Address(sender []byte) (string, error)
}

var registeredAuthenticators = make(map[string]Authenticator)

// RegisterAuthenticator registers an authenticator with a given name
func RegisterAuthenticator(name string, auth Authenticator) error {
name = strings.ToLower(name)
if _, ok := registeredAuthenticators[name]; ok {
return fmt.Errorf("%w: %s", ErrAuthenticatorExists, name)
}

registeredAuthenticators[name] = auth
return nil
}

// getAuthenticator returns an authenticator by the name it was registered with
func getAuthenticator(name string) (Authenticator, error) {
name = strings.ToLower(name)
auth, ok := registeredAuthenticators[name]
if !ok {
return nil, fmt.Errorf("%w: %s", ErrAuthenticatorNotFound, name)
}

return auth, nil
}

// GetAddress returns an address from a public key and authenticator type
func GetAddress(authType string, sender []byte) (string, error) {
auth, err := getAuthenticator(authType)
if err != nil {
return "", err
}

return auth.Address(sender)
}

var (
// ErrAuthenticatorExists is returned when an authenticator is already registered
ErrAuthenticatorExists = errors.New("authenticator already exists")
// ErrAuthenticatorNotFound is returned when an authenticator is not found
ErrAuthenticatorNotFound = errors.New("authenticator not found")
)
106 changes: 106 additions & 0 deletions pkg/auth/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package auth_test

import (
"testing"

"github.com/kwilteam/kwil-db/pkg/auth"
"github.com/kwilteam/kwil-db/pkg/crypto"
"github.com/stretchr/testify/assert"
)

const (
secp256k1Key = "f1aa5a7966c3863ccde3047f6a1e266cdc0c76b399e256b8fede92b1c69e4f4e"
ed25519Key = "7c67e60fce0c403ff40193a3128e5f3d8c2139aed36d76d7b5f1e70ec19c43f00aa611bf555596912bc6f9a9f169f8785918e7bab9924001895798ff13f05842"
)

func Test_Auth(t *testing.T) {

// testCase will take a signer
// it will sign a message and verify the signature using
// the proper authenticator. It will then check that the
// address is correct
type testCase struct {
name string
signer auth.Signer
address string
}

var msg = []byte("foo")

testCases := []testCase{
{
name: "eth personal sign",
signer: newEthSigner(secp256k1Key),
address: "0xc89D42189f0450C2b2c3c61f58Ec5d628176A1E7",
},
{
name: "cometbft secp256k1",
signer: newCometBftSigner(secp256k1Key),
address: "6E741B9E60A1DFB6FE40B53069CFBD00A6C1FC88",
},
{
name: "ed25519",
signer: newEd25519Signer(ed25519Key),
// ed25519 doesn't really have the concept of address, so it is just the hex public key
address: "0aa611bf555596912bc6f9a9f169f8785918e7bab9924001895798ff13f05842",
},
{
name: "near",
signer: newNearSigner(ed25519Key),
address: "0aa611bf555596912bc6f9a9f169f8785918e7bab9924001895798ff13f05842",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
sig, err := tc.signer.Sign(msg)
assert.NoError(t, err)

// verify the signature
err = sig.Verify(tc.signer.PublicKey(), msg)
assert.NoError(t, err)

// check the address
address, err := auth.GetAddress(sig.Type, tc.signer.PublicKey())
assert.NoError(t, err)

assert.Equal(t, tc.address, address)
})
}
}

func newEthSigner(pkey string) *auth.EthPersonalSigner {
secpKey, err := crypto.Secp256k1PrivateKeyFromHex(pkey)
if err != nil {
panic(err)
}

return &auth.EthPersonalSigner{Secp256k1PrivateKey: *secpKey}
}

func newCometBftSigner(pkey string) *auth.CometBftSecp256k1Signer {
secpKey, err := crypto.Secp256k1PrivateKeyFromHex(pkey)
if err != nil {
panic(err)
}

return &auth.CometBftSecp256k1Signer{Secp256k1PrivateKey: *secpKey}
}

func newEd25519Signer(pkey string) *auth.Ed25519Signer {
edKey, err := crypto.Ed25519PrivateKeyFromHex(pkey)
if err != nil {
panic(err)
}

return &auth.Ed25519Signer{Ed25519PrivateKey: *edKey}
}

func newNearSigner(pkey string) *auth.NearSigner {
edKey, err := crypto.Ed25519PrivateKeyFromHex(pkey)
if err != nil {
panic(err)
}

return &auth.NearSigner{Ed25519PrivateKey: *edKey}
}
Loading

0 comments on commit cbd615d

Please sign in to comment.