diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml new file mode 100644 index 0000000..ced4d9e --- /dev/null +++ b/.github/workflows/go.yaml @@ -0,0 +1,39 @@ +name: Go + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22.2' + cache-dependency-path: go.sum + + - name: Test + run: go test -v ./... + + linter: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: '1.22.2' + cache: false + + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + version: v1.58.1 + args: --timeout=30m --config=./golangci.pipeline.yml \ No newline at end of file diff --git a/.gitignore b/.gitignore index 723ef36..331c58f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +vendor \ No newline at end of file diff --git a/README.md b/README.md index 6157fca..c7da8bd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,53 @@ -# Documentation +# signature-sdk-go -## Introduction - -Welcome to the documentation for **inxy-payments/signature-sdk-go**! This library is designed to help you sign messages using a private key. Whether you're a beginner or an experienced developer, this guide will help you get the most out of this library. +The `signature-sdk-go` package provides functionality for signing messages using RSA private keys and verifying signatures using the corresponding RSA public keys. This package is useful for ensuring the integrity and authenticity of messages in your Go applications. ## Installation + +To use this package, you need to have Go installed. You can download it from [golang.org](https://golang.org/dl/). + +To include this package in your project, run: + +```sh +go get github.com/inxy-payments/signature-sdk-go +``` + +## Usage +Below is an example of how to use the signature-sdk-go package to sign a message and verify the signature. + +## Example + +```go +package main + +import ( + "fmt" + "github.com/inxy-payments/signature-sdk-go/pkg/converter" + "github.com/inxy-payments/signature-sdk-go/pkg/model" + rsaSignatureService "github.com/inxy-payments/signature-sdk-go/pkg/service/rsa" + "log" +) + +func main() { + const privateKeyExample = "MIIEowIBAAKCAQEAviXbecnlVp3qPbTAREhr5t8mDTLjJD3cE5SI8LsIjE2wbs23nkCYe47HveFJf+yqD1FqAaDYi+svRsPqVKVD/3HcAkx+Qn1cPQyVmFrbj0Q5U6vP7EuVi4ICG3BX5+l5DCAp5uIcLP9sr9h+4KxaMGaztYzutHjfsZRX99AwLJfw5axVyGIhZb3fZ1YyeI/P2AGQn8iY2XZQGYwc8emyqh3B0zByKLSMuuRDu20jZYXTrWDf+uZDSjZoqcXKmZfJIWxuufICa1H1xIxCxPjV91zG6AKPsqA74TbO91nZGE1yhPE/BA8dkgE+1NEQDWYNMs8cFqQLrLouRqY+g+HVzQIDAQABAoIBADXD+JooR2vFfS1zhYYJQFFouZaz09w0jZ0Pu+Ttzc32TbQXARuDQlp1le8P27uLTM7GA4ZwV6rAln6Y+RJ0JJT/OemAfZcJYWJ1w3rv/fM1pEwPYdx7xs5KtZPSoViXAL43/gEl4DetBat3OPEIavwSni/wqLJpFz9cJb+Ro32H//TECzivHvSxDDUrhMDTQHQeBw7ATiIVNT2iPutprKqjMNga4cg/vxm5BgiMTMjo2adbKQPKa4k5q3YOuFrkacjwbuRBpZtnqWd568moERMym8iHrdsUI/tgprQI7wxev/gj+nk5cbZoEr0fBvoTH/HDna3G5rGOE5uti5adn6ECgYEA6xvoG961ovmZinScEOx/xcrWT2Q1TuazOQesPf0ywfT/BAUCqxVQeEVHV78089HSP5QHHes5iq+MFAL8/hGlPq0EoHDDE1hyxS0gbZcR6oEmRKyOfSbShGn22Cuw0JWt7rOHzdHj8KCpZgpXLJUyKL0Tx2vCKaM3zb7lOFkIshkCgYEAzws06a5LJY4cuKjZkwews0MxCm7SpQXuoSnkOo1ROLukgJ209Le5IdNYC47GYDcwhkuY4tSRxyfq7rd4Upui9XjkaqiblpqOVcdajAI8XgmCbzwxaUcvomQpvC8lFocoOGtAw2P8TZ3WGOb3GoF/o1pQ0Dh9HLOrAPo79RONv9UCgYEA0s7L+SlhPgeF17KlOTuFecldDgSxE9UhwDIUC+Ua/PR7MJR5hwNuiti7ln8YsMJjPaSyGO6QQr0S4eKoC/uwahli+6UAFTmKdyf2Wq1JYDZ7JLqAbNFBk38b2UqbmPuM4GpTi4X2Vw0HtznwXkZMmmCm+nmxt/nkkHPpPfP/KwkCgYBQDphGJ2PdQKcwa/G9XYLgvgFvdEy1DKcp4CXk0hHu6vd/1/tJiOToBG2OAoYIXC7CLucOBn3b0T6RUZYP8yg+3KEN8OZAhMC2wF/ttUucXPb3hgHhIGp1018j6eLgZCCUODyRkM7VQEux01UHBb3R7zFCYiVWfM6JkTiv2gC8hQKBgHHFdpHeTu0vJf480UHd8e0vLfpRPqWhAaZBHRtY05Hv9/ClGR8sZ471e1Nk3LJNmOzzL/HN89oD8gHSJGmqHjmbUwpIQK8zCCpuwzAjbdghaHgupss4TJApnS8HuybW+eGBu/AIUlJqOCCImfoB5Gurk5VsjEpo2+lWIFKEJrlG" + + privateKey, err := converter.ToRSAPrivateKeyFromString(privateKeyExample) + if err != nil { + log.Fatal(err) + } + + service := rsaSignatureService.NewRSASignatureService(privateKey) + message := model.NewMessage("test message") + + signature, err := service.SignMessage(message) + if err != nil { + log.Fatal(err) + } + + fmt.Println(signature.Time) + fmt.Println(signature.Signature) +} + + + +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..62b6c74 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/inxy-payments/signature-sdk-go + +go 1.22.2 + +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..60ce688 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/golangci.pipeline.yml b/golangci.pipeline.yml new file mode 100644 index 0000000..a5289b7 --- /dev/null +++ b/golangci.pipeline.yml @@ -0,0 +1,57 @@ +# More info on config here: https://golangci-lint.run/usage/configuration/#config-file +run: + concurrency: 8 + timeout: 10m + issues-exit-code: 1 + tests: true + issues: + exclude-dirs: + - bin + - vendor + - var + - tmp + - .cache + exclude-files: + - \.pb\.go$ + - \.pb\.gw\.go$ + +output: + formats: + - format: colored-line-number + print-issued-lines: true + print-linter-name: true + +linters-settings: + govet: + shadow: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 2 + +linters: + disable-all: true + enable: + - errcheck + - goconst + - goimports + - gosec + - govet + - gosimple + - gofmt + - ineffassign + - revive + - typecheck + - unused + - staticcheck + +issues: + exclude-use-default: false + exclude: + # _ instead of err checks + - G104 + - exported func .* returns unexported types .*, which can be annoying to use + - should have a package comment + - don't use an underscore in package name + - or be unexported \ No newline at end of file diff --git a/pkg/converter/private_key.go b/pkg/converter/private_key.go new file mode 100644 index 0000000..c6c9c64 --- /dev/null +++ b/pkg/converter/private_key.go @@ -0,0 +1,21 @@ +package converter + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/base64" +) + +func ToRSAPrivateKeyFromString(privateKey string) (*rsa.PrivateKey, error) { + decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKey) + if err != nil { + return nil, err + } + + rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(decodedPrivateKey) + if err != nil { + return nil, err + } + + return rsaPrivateKey, nil +} diff --git a/pkg/converter/tests/to_rsa_private_key_from_string_test.go b/pkg/converter/tests/to_rsa_private_key_from_string_test.go new file mode 100644 index 0000000..3612791 --- /dev/null +++ b/pkg/converter/tests/to_rsa_private_key_from_string_test.go @@ -0,0 +1,75 @@ +package tests + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/asn1" + "encoding/base64" + "testing" + + "github.com/inxy-payments/signature-sdk-go/pkg/converter" + "github.com/stretchr/testify/assert" +) + +const privateKeyExample = "MIIEowIBAAKCAQEAviXbecnlVp3qPbTAREhr5t8mDTLjJD3cE5SI8LsIjE2wbs23nkCYe47HveFJf+yqD1FqAaDYi+svRsPqVKVD/3HcAkx+Qn1cPQyVmFrbj0Q5U6vP7EuVi4ICG3BX5+l5DCAp5uIcLP9sr9h+4KxaMGaztYzutHjfsZRX99AwLJfw5axVyGIhZb3fZ1YyeI/P2AGQn8iY2XZQGYwc8emyqh3B0zByKLSMuuRDu20jZYXTrWDf+uZDSjZoqcXKmZfJIWxuufICa1H1xIxCxPjV91zG6AKPsqA74TbO91nZGE1yhPE/BA8dkgE+1NEQDWYNMs8cFqQLrLouRqY+g+HVzQIDAQABAoIBADXD+JooR2vFfS1zhYYJQFFouZaz09w0jZ0Pu+Ttzc32TbQXARuDQlp1le8P27uLTM7GA4ZwV6rAln6Y+RJ0JJT/OemAfZcJYWJ1w3rv/fM1pEwPYdx7xs5KtZPSoViXAL43/gEl4DetBat3OPEIavwSni/wqLJpFz9cJb+Ro32H//TECzivHvSxDDUrhMDTQHQeBw7ATiIVNT2iPutprKqjMNga4cg/vxm5BgiMTMjo2adbKQPKa4k5q3YOuFrkacjwbuRBpZtnqWd568moERMym8iHrdsUI/tgprQI7wxev/gj+nk5cbZoEr0fBvoTH/HDna3G5rGOE5uti5adn6ECgYEA6xvoG961ovmZinScEOx/xcrWT2Q1TuazOQesPf0ywfT/BAUCqxVQeEVHV78089HSP5QHHes5iq+MFAL8/hGlPq0EoHDDE1hyxS0gbZcR6oEmRKyOfSbShGn22Cuw0JWt7rOHzdHj8KCpZgpXLJUyKL0Tx2vCKaM3zb7lOFkIshkCgYEAzws06a5LJY4cuKjZkwews0MxCm7SpQXuoSnkOo1ROLukgJ209Le5IdNYC47GYDcwhkuY4tSRxyfq7rd4Upui9XjkaqiblpqOVcdajAI8XgmCbzwxaUcvomQpvC8lFocoOGtAw2P8TZ3WGOb3GoF/o1pQ0Dh9HLOrAPo79RONv9UCgYEA0s7L+SlhPgeF17KlOTuFecldDgSxE9UhwDIUC+Ua/PR7MJR5hwNuiti7ln8YsMJjPaSyGO6QQr0S4eKoC/uwahli+6UAFTmKdyf2Wq1JYDZ7JLqAbNFBk38b2UqbmPuM4GpTi4X2Vw0HtznwXkZMmmCm+nmxt/nkkHPpPfP/KwkCgYBQDphGJ2PdQKcwa/G9XYLgvgFvdEy1DKcp4CXk0hHu6vd/1/tJiOToBG2OAoYIXC7CLucOBn3b0T6RUZYP8yg+3KEN8OZAhMC2wF/ttUucXPb3hgHhIGp1018j6eLgZCCUODyRkM7VQEux01UHBb3R7zFCYiVWfM6JkTiv2gC8hQKBgHHFdpHeTu0vJf480UHd8e0vLfpRPqWhAaZBHRtY05Hv9/ClGR8sZ471e1Nk3LJNmOzzL/HN89oD8gHSJGmqHjmbUwpIQK8zCCpuwzAjbdghaHgupss4TJApnS8HuybW+eGBu/AIUlJqOCCImfoB5Gurk5VsjEpo2+lWIFKEJrlG" + +func TestToRSAPrivateKeyFromString(t *testing.T) { + type args struct { + privateKey string + } + + decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKeyExample) + if err != nil { + t.Fatal(err) + } + + rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(decodedPrivateKey) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + args args + want *rsa.PrivateKey + err error + }{ + { + name: "success", + args: args{ + privateKey: privateKeyExample, + }, + want: rsaPrivateKey, + err: nil, + }, + { + name: "fail base64", + args: args{ + privateKey: "a", + }, + want: nil, + err: base64.CorruptInputError(0), + }, + { + name: "fail private key", + args: args{ + privateKey: base64.StdEncoding.EncodeToString([]byte("test")), + }, + want: nil, + err: asn1.StructuralError{Msg: "tags don't match (16 vs {class:1 tag:20 length:101 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} pkcs1PrivateKey @2"}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + privateKey, err := converter.ToRSAPrivateKeyFromString(tt.args.privateKey) + + assert.Equal(t, tt.want, privateKey) + assert.Equal(t, tt.err, err) + + }) + } +} diff --git a/pkg/model/message.go b/pkg/model/message.go new file mode 100644 index 0000000..10b8412 --- /dev/null +++ b/pkg/model/message.go @@ -0,0 +1,22 @@ +package model + +import "time" + +type Message struct { + Payload string `json:"payload"` + Time int64 `json:"time"` +} + +func NewMessage(payload string) Message { + return Message{ + Payload: payload, + Time: time.Now().Unix(), + } +} + +func NewMessageWithTimestamp(payload string, time int64) Message { + return Message{ + Payload: payload, + Time: time, + } +} diff --git a/pkg/model/signature.go b/pkg/model/signature.go new file mode 100644 index 0000000..41f47dc --- /dev/null +++ b/pkg/model/signature.go @@ -0,0 +1,6 @@ +package model + +type Signature struct { + Time int64 `json:"time"` + Signature string `json:"signature"` +} diff --git a/pkg/service/rsa/service.go b/pkg/service/rsa/service.go new file mode 100644 index 0000000..37206a9 --- /dev/null +++ b/pkg/service/rsa/service.go @@ -0,0 +1,15 @@ +package rsa + +import ( + "crypto/rsa" + + "github.com/inxy-payments/signature-sdk-go/pkg/service" +) + +type rsaSignatureService struct { + privateKey *rsa.PrivateKey +} + +func NewRSASignatureService(privateKey *rsa.PrivateKey) service.SignatureService { + return &rsaSignatureService{privateKey: privateKey} +} diff --git a/pkg/service/rsa/sign_message.go b/pkg/service/rsa/sign_message.go new file mode 100644 index 0000000..762de9c --- /dev/null +++ b/pkg/service/rsa/sign_message.go @@ -0,0 +1,27 @@ +package rsa + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "encoding/base64" + "strconv" + "strings" + + "github.com/inxy-payments/signature-sdk-go/pkg/model" +) + +func (rss *rsaSignatureService) SignMessage(message model.Message) (*model.Signature, error) { + payload := strings.ToLower(message.Payload) + "_" + strconv.Itoa(int(message.Time)) + hashed := sha256.Sum256([]byte(payload)) + signature, err := rsa.SignPKCS1v15(rand.Reader, rss.privateKey, crypto.SHA256, hashed[:]) + if err != nil { + return nil, err + } + + return &model.Signature{ + Time: message.Time, + Signature: base64.StdEncoding.EncodeToString(signature), + }, nil +} diff --git a/pkg/service/rsa/tests/sign_message_test.go b/pkg/service/rsa/tests/sign_message_test.go new file mode 100644 index 0000000..4370832 --- /dev/null +++ b/pkg/service/rsa/tests/sign_message_test.go @@ -0,0 +1,91 @@ +package tests + +import ( + "crypto" + "crypto/rsa" + "crypto/sha256" + "encoding/base64" + "strconv" + "strings" + "testing" + "time" + + "github.com/inxy-payments/signature-sdk-go/pkg/converter" + "github.com/inxy-payments/signature-sdk-go/pkg/model" + rsaService "github.com/inxy-payments/signature-sdk-go/pkg/service/rsa" + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" +) + +const privateKeyExample = "MIIEowIBAAKCAQEAviXbecnlVp3qPbTAREhr5t8mDTLjJD3cE5SI8LsIjE2wbs23nkCYe47HveFJf+yqD1FqAaDYi+svRsPqVKVD/3HcAkx+Qn1cPQyVmFrbj0Q5U6vP7EuVi4ICG3BX5+l5DCAp5uIcLP9sr9h+4KxaMGaztYzutHjfsZRX99AwLJfw5axVyGIhZb3fZ1YyeI/P2AGQn8iY2XZQGYwc8emyqh3B0zByKLSMuuRDu20jZYXTrWDf+uZDSjZoqcXKmZfJIWxuufICa1H1xIxCxPjV91zG6AKPsqA74TbO91nZGE1yhPE/BA8dkgE+1NEQDWYNMs8cFqQLrLouRqY+g+HVzQIDAQABAoIBADXD+JooR2vFfS1zhYYJQFFouZaz09w0jZ0Pu+Ttzc32TbQXARuDQlp1le8P27uLTM7GA4ZwV6rAln6Y+RJ0JJT/OemAfZcJYWJ1w3rv/fM1pEwPYdx7xs5KtZPSoViXAL43/gEl4DetBat3OPEIavwSni/wqLJpFz9cJb+Ro32H//TECzivHvSxDDUrhMDTQHQeBw7ATiIVNT2iPutprKqjMNga4cg/vxm5BgiMTMjo2adbKQPKa4k5q3YOuFrkacjwbuRBpZtnqWd568moERMym8iHrdsUI/tgprQI7wxev/gj+nk5cbZoEr0fBvoTH/HDna3G5rGOE5uti5adn6ECgYEA6xvoG961ovmZinScEOx/xcrWT2Q1TuazOQesPf0ywfT/BAUCqxVQeEVHV78089HSP5QHHes5iq+MFAL8/hGlPq0EoHDDE1hyxS0gbZcR6oEmRKyOfSbShGn22Cuw0JWt7rOHzdHj8KCpZgpXLJUyKL0Tx2vCKaM3zb7lOFkIshkCgYEAzws06a5LJY4cuKjZkwews0MxCm7SpQXuoSnkOo1ROLukgJ209Le5IdNYC47GYDcwhkuY4tSRxyfq7rd4Upui9XjkaqiblpqOVcdajAI8XgmCbzwxaUcvomQpvC8lFocoOGtAw2P8TZ3WGOb3GoF/o1pQ0Dh9HLOrAPo79RONv9UCgYEA0s7L+SlhPgeF17KlOTuFecldDgSxE9UhwDIUC+Ua/PR7MJR5hwNuiti7ln8YsMJjPaSyGO6QQr0S4eKoC/uwahli+6UAFTmKdyf2Wq1JYDZ7JLqAbNFBk38b2UqbmPuM4GpTi4X2Vw0HtznwXkZMmmCm+nmxt/nkkHPpPfP/KwkCgYBQDphGJ2PdQKcwa/G9XYLgvgFvdEy1DKcp4CXk0hHu6vd/1/tJiOToBG2OAoYIXC7CLucOBn3b0T6RUZYP8yg+3KEN8OZAhMC2wF/ttUucXPb3hgHhIGp1018j6eLgZCCUODyRkM7VQEux01UHBb3R7zFCYiVWfM6JkTiv2gC8hQKBgHHFdpHeTu0vJf480UHd8e0vLfpRPqWhAaZBHRtY05Hv9/ClGR8sZ471e1Nk3LJNmOzzL/HN89oD8gHSJGmqHjmbUwpIQK8zCCpuwzAjbdghaHgupss4TJApnS8HuybW+eGBu/AIUlJqOCCImfoB5Gurk5VsjEpo2+lWIFKEJrlG" + +func TestSignMessage(t *testing.T) { + privateKey, err := converter.ToRSAPrivateKeyFromString(privateKeyExample) + if err != nil { + t.Fatal(err) + } + + timestamp := time.Now().Unix() + + type args struct { + payload string + timestamp int64 + privateKey *rsa.PrivateKey + } + + tests := []struct { + name string + args args + want *model.Signature + err error + }{ + { + name: "success", + args: args{ + payload: "TestSignMessage", + timestamp: timestamp, + privateKey: privateKey, + }, + want: &model.Signature{ + Time: timestamp, + }, + err: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var signature *model.Signature + + service := rsaService.NewRSASignatureService(tt.args.privateKey) + message := model.NewMessageWithTimestamp(tt.args.payload, tt.args.timestamp) + + signature, err = service.SignMessage(message) + if tt.err != nil && err != nil { + require.Equal(t, tt.err.Error(), err.Error()) + + return + } + + require.Equal(t, tt.want.Time, signature.Time) + + var signedMessageBytes []byte + + signedMessageBytes, err = base64.StdEncoding.DecodeString(signature.Signature) + if err != nil { + t.Fatal(err) + } + + payload := strings.ToLower(tt.args.payload) + "_" + strconv.Itoa(int(tt.args.timestamp)) + hashed := sha256.Sum256([]byte(payload)) + + err = rsa.VerifyPKCS1v15(&privateKey.PublicKey, crypto.SHA256, hashed[:], signedMessageBytes) + + assert.NoError(t, err) + }) + } +} diff --git a/pkg/service/service.go b/pkg/service/service.go new file mode 100644 index 0000000..8e14834 --- /dev/null +++ b/pkg/service/service.go @@ -0,0 +1,7 @@ +package service + +import "github.com/inxy-payments/signature-sdk-go/pkg/model" + +type SignatureService interface { + SignMessage(message model.Message) (*model.Signature, error) +}