Skip to content

Commit 9557499

Browse files
namer/signer/verifier: implementation
Closes TNTP-4190
1 parent 3161b96 commit 9557499

File tree

4 files changed

+366
-8
lines changed

4 files changed

+366
-8
lines changed

hasher/hasher_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ func TestSHA256Hasher(t *testing.T) {
6161
t.Parallel()
6262

6363
tests := []struct {
64-
name string
65-
in []byte
66-
out string
64+
name string
65+
in []byte
66+
expected string
6767
}{
6868
{"empty", []byte(""), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
6969
{"abc", []byte("abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"},
@@ -77,7 +77,7 @@ func TestSHA256Hasher(t *testing.T) {
7777

7878
result, _ := h.Hash(test.in)
7979

80-
assert.Equal(t, test.out, hex.EncodeToString(result))
80+
assert.Equal(t, test.expected, hex.EncodeToString(result))
8181
})
8282
}
8383
}

marshaller/marshaller.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,24 @@ var ErrUnmarshall = errors.New("failed to unmarshal")
1717
// implements one time for all objects.
1818
// Required for `integrity.Storage` to set marshalling format for any type object
1919
// and as recommendation for developers of `Storage` wrappers.
20-
type DefaultMarshaller interface {
20+
type DefaultMarshaller interface { //nolint:iface
2121
Marshal(data any) ([]byte, error)
2222
Unmarshal(data []byte, out any) error
2323
}
2424

2525
// Marshallable - custom object serialization, implements for each object.
2626
// Required for `integrity.Storage` type to set marshalling format to specific object
2727
// and as recommendation for developers of `Storage` wrappers.
28-
type Marshallable interface {
29-
Marshal() ([]byte, error)
28+
type Marshallable interface { //nolint:iface
29+
Marshal(data any) ([]byte, error)
3030
Unmarshal(data []byte, out any) error
3131
}
3232

3333
// YAMLMarshaller struct represent realization.
3434
type YAMLMarshaller struct{}
3535

3636
// NewYamlMarshaller creates new NewYamlMarshaller object.
37-
func NewYamlMarshaller() YAMLMarshaller {
37+
func NewYamlMarshaller() Marshallable {
3838
return YAMLMarshaller{}
3939
}
4040

namer/namer.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22
package namer
33

44
import (
5+
"bytes"
6+
"errors"
7+
"fmt"
8+
"strings"
9+
10+
"github.com/tarantool/go-storage/crypto"
11+
"github.com/tarantool/go-storage/hasher"
512
"github.com/tarantool/go-storage/kv"
13+
"github.com/tarantool/go-storage/marshaller"
614
)
715

816
// KeyType represents key types.
@@ -17,6 +25,19 @@ const (
1725
KeyTypeSignature
1826
)
1927

28+
const (
29+
hashName = "hash"
30+
sigName = "sig"
31+
namesNumber = 3
32+
)
33+
34+
var (
35+
// ErrInvalidKey is returned when missing key, hash or signature.
36+
ErrInvalidKey = errors.New("missing key, hash or signature")
37+
// ErrHashMismatch is returned when hash mismatch.
38+
ErrHashMismatch = errors.New("hash mismatch")
39+
)
40+
2041
// Key implements internal realization.
2142
type Key struct {
2243
Name string // Object identificator.
@@ -30,6 +51,69 @@ type Namer interface {
3051
ParseNames(names []string) []Key // Convert names into keys.
3152
}
3253

54+
// -----------------------------------------------------------------------------
55+
56+
// DefaultNamer represents default namer.
57+
type DefaultNamer struct {
58+
prefix string
59+
}
60+
61+
// NewDefaultNamer returns new DefaultNamer object.
62+
func NewDefaultNamer(prefix string) *DefaultNamer {
63+
return &DefaultNamer{
64+
prefix: prefix,
65+
}
66+
}
67+
68+
// GenerateNames generates set on names from basic name.
69+
func (n *DefaultNamer) GenerateNames(name string) []string {
70+
return []string{
71+
n.prefix + "/" + name,
72+
n.prefix + "/" + hashName + "/" + name,
73+
n.prefix + "/" + sigName + "/" + name,
74+
}
75+
}
76+
77+
// ParseNames returns set of Keys with different types.
78+
func (n *DefaultNamer) ParseNames(names []string) []Key {
79+
keys := make([]Key, 0, namesNumber)
80+
81+
for _, name := range names {
82+
var key Key
83+
84+
// Remove prefix.
85+
result := strings.ReplaceAll(name, n.prefix, "")
86+
87+
parts := strings.Split(result, "/")
88+
89+
key.Name = name
90+
91+
switch parts[1] {
92+
case "all":
93+
{
94+
key.Property = ""
95+
key.Type = KeyTypeValue
96+
}
97+
case "hash":
98+
{
99+
key.Property = ""
100+
key.Type = KeyTypeHash
101+
}
102+
case "sig":
103+
{
104+
key.Property = ""
105+
key.Type = KeyTypeSignature
106+
}
107+
}
108+
109+
keys = append(keys, key)
110+
}
111+
112+
return keys
113+
}
114+
115+
//-----------------------------------------------------------------------------
116+
33117
// Generator generates signer K/V pairs.
34118
// Implementation should use `generic` and will used for strong typing of the solution.
35119
type Generator[T any] interface {
@@ -40,3 +124,123 @@ type Generator[T any] interface {
40124
type Validator[T any] interface {
41125
Validate(pairs []kv.KeyValue) (T, error)
42126
}
127+
128+
//-----------------------------------------------------------------------------
129+
130+
// DefaultGeneratorValidator represent default generator-validator.
131+
type DefaultGeneratorValidator[T any] struct {
132+
Namer Namer
133+
Hasher hasher.Hasher
134+
SignerVerifier crypto.SignerVerifier
135+
Marshaller marshaller.Marshallable
136+
}
137+
138+
// NewDefaultGeneratorValidator returns new object.
139+
func NewDefaultGeneratorValidator[T any](
140+
namer Namer,
141+
hasher hasher.Hasher,
142+
signverifier crypto.SignerVerifier,
143+
marshaller marshaller.Marshallable,
144+
) DefaultGeneratorValidator[T] {
145+
return DefaultGeneratorValidator[T]{
146+
Namer: namer,
147+
Hasher: hasher,
148+
SignerVerifier: signverifier,
149+
Marshaller: marshaller,
150+
}
151+
}
152+
153+
// Generate create KV pairs with value, hash and signature.
154+
func (gv DefaultGeneratorValidator[T]) Generate(name string, value T) ([]kv.KeyValue, error) {
155+
var kvList []kv.KeyValue
156+
157+
blob, err := gv.Marshaller.Marshal(value)
158+
if err != nil {
159+
return nil, fmt.Errorf("failed to marshal: %w", err)
160+
}
161+
162+
hash, err := gv.Hasher.Hash(blob)
163+
if err != nil {
164+
return nil, fmt.Errorf("failed to hash: %w", err)
165+
}
166+
167+
signature, err := gv.SignerVerifier.Sign(hash)
168+
if err != nil {
169+
return nil, fmt.Errorf("failed to sign: %w", err)
170+
}
171+
172+
names := gv.Namer.GenerateNames(name)
173+
keys := gv.Namer.ParseNames(names)
174+
175+
for _, key := range keys {
176+
switch key.Type {
177+
case KeyTypeValue:
178+
{
179+
kvList = append(kvList, kv.KeyValue{
180+
Key: []byte(key.Name),
181+
Value: blob,
182+
ModRevision: 1,
183+
})
184+
}
185+
case KeyTypeHash:
186+
{
187+
kvList = append(kvList, kv.KeyValue{
188+
Key: []byte(key.Name),
189+
Value: hash,
190+
ModRevision: 1,
191+
})
192+
}
193+
case KeyTypeSignature:
194+
{
195+
kvList = append(kvList, kv.KeyValue{
196+
Key: []byte(key.Name),
197+
Value: signature,
198+
ModRevision: 1,
199+
})
200+
}
201+
}
202+
}
203+
204+
return kvList, nil
205+
}
206+
207+
// Validate checks hash match, verify signature, unmarshall object and return it.
208+
func (gv DefaultGeneratorValidator[T]) Validate(pairs []kv.KeyValue) (T, error) {
209+
var value T
210+
211+
var blob []byte
212+
213+
var hash, signature []byte
214+
215+
for _, keyvalue := range pairs {
216+
switch {
217+
case strings.Contains(string(keyvalue.Key), hashName):
218+
hash = keyvalue.Value
219+
case strings.Contains(string(keyvalue.Key), sigName):
220+
signature = keyvalue.Value
221+
default:
222+
blob = keyvalue.Value
223+
}
224+
}
225+
226+
if blob == nil || hash == nil || signature == nil {
227+
return value, ErrInvalidKey
228+
}
229+
230+
err := gv.SignerVerifier.Verify(hash, signature)
231+
if err != nil {
232+
return value, fmt.Errorf("signature verification failed: %w", err)
233+
}
234+
235+
computedHash, err := gv.Hasher.Hash(blob)
236+
if !bytes.Equal(computedHash, hash) || err != nil {
237+
return value, ErrHashMismatch
238+
}
239+
240+
err = gv.Marshaller.Unmarshal(blob, &value)
241+
if err != nil {
242+
return value, fmt.Errorf("failed to unmarshal: %w", err)
243+
}
244+
245+
return value, nil
246+
}

0 commit comments

Comments
 (0)