Skip to content

Commit

Permalink
added extensible auth using build tags (#339)
Browse files Browse the repository at this point in the history
* added extensible auth using build tags

* go mod tidied

* made gavins requested changes
  • Loading branch information
brennanjl committed Feb 26, 2024
1 parent c4dfa8d commit 3bdb61f
Show file tree
Hide file tree
Showing 18 changed files with 235 additions and 372 deletions.
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ tasks:
test:unit:
desc: Run unit tests
cmds:
- go test $(go list ./... | grep -v /kwil-db\/test/) -count=1
- go test $(go list ./... | grep -v /kwil-db\/test/) -tags=ext_test -count=1

test:unit:race:
desc: Run unit tests with race
Expand Down
2 changes: 1 addition & 1 deletion cmd/kwil-cli/cmds/utils/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func getExampleTxQueryResponse() *types.TcTxQueryResponse {
secp256k1EpSigBytes, _ := hex.DecodeString(secp256k1EpSigHex)
secpSig := auth.Signature{
Signature: secp256k1EpSigBytes,
Type: auth.EthAuth,
Type: auth.EthPersonalSignAuth,
}

rawPayload := transactions.ActionExecution{
Expand Down
2 changes: 2 additions & 0 deletions cmd/kwild/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/viper"

_ "github.com/kwilteam/kwil-db/extensions/auth"
)

var (
Expand Down
21 changes: 21 additions & 0 deletions extensions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Extensions

Extensions are compile-time loaded pieces of code that impact core `kwild` functionality. Typically, extensions impact core consensus code, and therefore great care should be taken when implementing and choosing to use certain extensions.

## Interfaces and Drivers

Extensions can be made by implementing a driver for one of many interfaces. These implementations should be registered using Go's `init()` function, which will register the driver when the package is loaded. This is conceptually similar to Go's `database/sql` package, where users can implement custom `database/sql/driver/Driver` implementations.

## Build Tags

To include an extension in a build, users should use [Go's build tags](<https://www.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags>). Users can specify what extensions they include by including their respective tags:

### Tag Naming

While you can give any name to your extension's tag, this repo adopts the best practice of prefixing the type of extension with the rest of the name. For example, if we were adding an extension that added standard RSA signatures for authentication, we might name the build tag `auth_rsa`. We could then include this by running:

```bash
go build -tags auth_rsa
```

Additionally, the build tag `ext_test` is added if the extension should be included as a part of `kwild`'s automated testing.
1 change: 1 addition & 0 deletions extensions/auth/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package auth
58 changes: 58 additions & 0 deletions extensions/auth/ed25519_sha256.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//go:build auth_ed25519_sha256 || ext_test

package auth

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

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

func init() {
err := auth.RegisterAuthenticator(Ed25519Sha256Auth, Ed22519Sha256Authenticator{})
if err != nil {
panic(err)
}
}

const (
// Ed25519Sha256Auth is the authenticator name
// the "nr" suffix is for NEAR, and provides backwards compatibility
Ed25519Sha256Auth = "ed25519_nr"
// ed25519SignatureLength is the expected length of a signature
ed25519SignatureLength = 64
)

// Ed22519Sha256Authenticator is an authenticator that applies the sha256 hash to the message
// before verifying the signature. This is a common standard in ecosystems like NEAR.
type Ed22519Sha256Authenticator struct{}

var _ auth.Authenticator = Ed22519Sha256Authenticator{}

// Address generates a NEAR implicit address from a public key
func (e Ed22519Sha256Authenticator) Address(publicKey []byte) (string, error) {
if len(publicKey) != ed25519.PublicKeySize {
return "", fmt.Errorf("invalid ed25519 public key size for generating near address: %d", len(publicKey))
}

return hex.EncodeToString(publicKey), nil
}

// Verify verifies the signature against the given public key and data.
func (e Ed22519Sha256Authenticator) Verify(publicKey []byte, msg []byte, signature []byte) error {
pubkey, err := crypto.Ed25519PublicKeyFromBytes(publicKey)
if err != nil {
return err
}

if len(signature) != ed25519SignatureLength {
return fmt.Errorf("invalid signature length: expected %d, received %d", ed25519SignatureLength, len(signature))
}

hash := sha256.Sum256(msg)
return pubkey.Verify(signature, hash[:])
}
27 changes: 27 additions & 0 deletions extensions/auth/ed25519_sha256_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build auth_ed25519_sha256 || ext_test

package auth_test

import (
"encoding/hex"
"testing"

"github.com/kwilteam/kwil-db/extensions/auth"
"github.com/stretchr/testify/require"
)

func Test_Ed25519Sha256Near(t *testing.T) {
publicKey := "0aa611bf555596912bc6f9a9f169f8785918e7bab9924001895798ff13f05842"
signature := "089bcf52220dad77abc2cfcb1639bcb2944fdf64e0b173f40cd0d144bdbf7808f4eff3716eb3e98ed40be3ab126e1449d5f57efbe5626673059edc90e9cd9801"
message := []byte("foo")
pubKeyBts, err := hex.DecodeString(publicKey)
require.NoError(t, err, "error decode public key")

signatureBts, err := hex.DecodeString(signature)
require.NoError(t, err, "error decode signature")

authenticator := auth.Ed22519Sha256Authenticator{}

err = authenticator.Verify(pubKeyBts, message, signatureBts)
require.NoError(t, err, "error verifying signature")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ require (
github.com/tidwall/wal v1.1.7
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346
go.uber.org/zap v1.25.0
golang.org/x/crypto v0.12.0
golang.org/x/sync v0.3.0
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e
google.golang.org/grpc v1.57.0
Expand Down Expand Up @@ -222,6 +221,7 @@ require (
go.opentelemetry.io/otel/trace v1.15.1 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
Expand Down
28 changes: 0 additions & 28 deletions pkg/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,12 @@ func Test_Auth(t *testing.T) {
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 {
Expand Down Expand Up @@ -78,15 +68,6 @@ func newEthSigner(pkey string) *auth.EthPersonalSigner {
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 {
Expand All @@ -95,12 +76,3 @@ func newEd25519Signer(pkey string) *auth.Ed25519Signer {

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 3bdb61f

Please sign in to comment.