/
multi_ed25519.go
92 lines (78 loc) · 2.59 KB
/
multi_ed25519.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0
package diemkeys
import (
"crypto/ed25519"
"encoding/hex"
)
const (
// BitmapNumOfBytes defines length of bitmap appended to multi-signed signature
BitmapNumOfBytes = 4
// MaxNumOfKeys defines max number of keys a multi sig keys can have
MaxNumOfKeys = 32
)
// MultiEd25519PublicKey implements `PublicKey` interface with multi ed25519 sig support
type MultiEd25519PublicKey struct {
keys []ed25519.PublicKey
threshold byte
}
// MultiEd25519PrivateKey implements `PrivateKey` interface with multi ed25519 sig support
type MultiEd25519PrivateKey struct {
keys []ed25519.PrivateKey
threshold byte
}
// NewMultiEd25519PublicKey creates new `MultiEd25519PublicKey` as `PublicKey`
// with given keys and threshold
func NewMultiEd25519PublicKey(keys []ed25519.PublicKey, threshold byte) PublicKey {
validate(len(keys), threshold)
return &MultiEd25519PublicKey{keys, threshold}
}
// NewMultiEd25519PrivateKey creates new `MultiEd25519PrivateKey` as `PrivateKey`
// with given keys and threshold
func NewMultiEd25519PrivateKey(keys []ed25519.PrivateKey, threshold byte) PrivateKey {
validate(len(keys), threshold)
return &MultiEd25519PrivateKey{keys, threshold}
}
func validate(keysLen int, threshold byte) {
if keysLen == 0 {
panic("should at least have 1 key")
}
if int(threshold) > keysLen {
panic("threshold should be less or equal to len(keys)")
}
if keysLen > MaxNumOfKeys {
panic("len(keys) is more than max num of keys")
}
}
// IsMulti returns true
func (k *MultiEd25519PublicKey) IsMulti() bool {
return true
}
// Hex implements `PublicKey` interface returns hex-encoded string of public keys' bytes
func (k *MultiEd25519PublicKey) Hex() string {
return hex.EncodeToString(k.Bytes())
}
// Bytes returns bytes representation of Diem MultiEd25519 public key
func (k *MultiEd25519PublicKey) Bytes() []byte {
var ret []byte
for _, key := range k.keys {
ret = append(ret, key...)
}
return append(ret, k.threshold)
}
// Sign implements `PrivateKey` interface, signs arbitrary message bytes and return it's signature.
func (k *MultiEd25519PrivateKey) Sign(msg []byte) []byte {
var bitmap [BitmapNumOfBytes]byte
var ret []byte
for i, key := range k.keys[:k.threshold] {
bitmapSetBit(&bitmap, byte(i))
ret = append(ret, ed25519.Sign(key, msg)...)
}
return append(ret, bitmap[:]...)
}
func bitmapSetBit(input *[BitmapNumOfBytes]byte, index byte) {
bucket := index / 8
// It's always invoked with index < 32, thus there is no need to check range.
pos := index - (bucket * 8)
input[bucket] |= uint8(128 >> pos)
}