forked from hyperledger/fabric
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signer.go
97 lines (83 loc) · 2.06 KB
/
signer.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
93
94
95
96
97
/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package discovery
import (
"encoding/hex"
"sync"
"github.com/hyperledger/fabric/common/util"
)
// MemoizeSigner signs messages with the same signature
// if the message was signed recently
type MemoizeSigner struct {
maxEntries uint
sync.RWMutex
memory map[string][]byte
sign Signer
}
// NewMemoizeSigner creates a new MemoizeSigner that signs
// message with the given sign function
func NewMemoizeSigner(signFunc Signer, maxEntries uint) *MemoizeSigner {
return &MemoizeSigner{
maxEntries: maxEntries,
memory: make(map[string][]byte),
sign: signFunc,
}
}
// Signer signs a message and returns the signature and nil,
// or nil and error on failure
func (ms *MemoizeSigner) Sign(msg []byte) ([]byte, error) {
sig, isInMemory := ms.lookup(msg)
if isInMemory {
return sig, nil
}
sig, err := ms.sign(msg)
if err != nil {
return nil, err
}
ms.memorize(msg, sig)
return sig, nil
}
// lookup looks up the given message in memory and returns
// the signature, if the message is in memory
func (ms *MemoizeSigner) lookup(msg []byte) ([]byte, bool) {
ms.RLock()
defer ms.RUnlock()
sig, exists := ms.memory[msgDigest(msg)]
return sig, exists
}
func (ms *MemoizeSigner) memorize(msg, signature []byte) {
if ms.maxEntries == 0 {
return
}
ms.RLock()
shouldShrink := len(ms.memory) >= (int)(ms.maxEntries)
ms.RUnlock()
if shouldShrink {
ms.shrinkMemory()
}
ms.Lock()
defer ms.Unlock()
ms.memory[msgDigest(msg)] = signature
}
// evict evicts random messages from memory
// until its size is smaller than maxEntries
func (ms *MemoizeSigner) shrinkMemory() {
ms.Lock()
defer ms.Unlock()
for len(ms.memory) > (int)(ms.maxEntries) {
ms.evictFromMemory()
}
}
// evictFromMemory evicts a random message from memory
func (ms *MemoizeSigner) evictFromMemory() {
for dig := range ms.memory {
delete(ms.memory, dig)
return
}
}
// msgDigest returns a digest of a given message
func msgDigest(msg []byte) string {
return hex.EncodeToString(util.ComputeSHA256(msg))
}