-
Notifications
You must be signed in to change notification settings - Fork 179
/
combine.go
74 lines (60 loc) · 2.29 KB
/
combine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package signature
import (
"encoding/binary"
"fmt"
"github.com/onflow/flow-go/crypto"
)
// lengthSize is how many bytes we use to encode the length of each signature.
const lengthSize = 4
// Combiner creates a simple implementation for joining and splitting signatures
// on a level above the cryptographic implementation. It simply concatenates
// signatures together with their length information and uses this information
// to split the concatenated bytes into its signature parts again.
type Combiner struct{}
// NewCombiner creates a new combiner to join and split signatures.
func NewCombiner() *Combiner {
c := &Combiner{}
return c
}
// Join will concatenate the provided signatures into a common byte slice, with
// added length information. It will never fail.
func (c *Combiner) Join(sigs ...crypto.Signature) ([]byte, error) {
var combined []byte
for _, sig := range sigs {
length := make([]byte, 4)
binary.LittleEndian.PutUint32(length, uint32(len(sig)))
combined = append(combined, length...)
combined = append(combined, sig...)
}
return combined, nil
}
// Split will split the given byte slice into its signature parts, using the
// embedded length information. If any length is invalid, it will fail.
func (c *Combiner) Split(combined []byte) ([]crypto.Signature, error) {
var sigs []crypto.Signature
for next := 0; next < len(combined); {
// check that we have at least 4 bytes of length information
remaining := len(combined) - next
if remaining < lengthSize {
return nil, fmt.Errorf("insufficient remaining bytes for length information (remaining: %d, min: %d)", remaining, 4)
}
// get the next length information
length := int(binary.LittleEndian.Uint32(combined[next : next+4]))
// create the beginning marker for the signature
from := next + lengthSize
if from >= len(combined) {
return nil, fmt.Errorf("invalid from marker for next signature (from: %d, max: %d)", from, len(combined)-1)
}
// create the end marker for the signature
to := from + length
if to > len(combined) {
return nil, fmt.Errorf("invalid to marker for next signature (to: %d, max: %d)", to, len(combined))
}
// get the signature
sig := make([]byte, length)
copy(sig[:], combined[from:to])
sigs = append(sigs, sig)
next = next + lengthSize + length
}
return sigs, nil
}