github.com/hyperledger-labs/bdls@v2.1.1+incompatible/discovery/client/signer.go (about)

     1  /*
     2  Copyright IBM Corp All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package discovery
     8  
     9  import (
    10  	"encoding/hex"
    11  	"sync"
    12  
    13  	"github.com/hyperledger/fabric/common/util"
    14  )
    15  
    16  // MemoizeSigner signs messages with the same signature
    17  // if the message was signed recently
    18  type MemoizeSigner struct {
    19  	maxEntries uint
    20  	sync.RWMutex
    21  	memory map[string][]byte
    22  	sign   Signer
    23  }
    24  
    25  // NewMemoizeSigner creates a new MemoizeSigner that signs
    26  // message with the given sign function
    27  func NewMemoizeSigner(signFunc Signer, maxEntries uint) *MemoizeSigner {
    28  	return &MemoizeSigner{
    29  		maxEntries: maxEntries,
    30  		memory:     make(map[string][]byte),
    31  		sign:       signFunc,
    32  	}
    33  }
    34  
    35  // Signer signs a message and returns the signature and nil,
    36  // or nil and error on failure
    37  func (ms *MemoizeSigner) Sign(msg []byte) ([]byte, error) {
    38  	sig, isInMemory := ms.lookup(msg)
    39  	if isInMemory {
    40  		return sig, nil
    41  	}
    42  	sig, err := ms.sign(msg)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	ms.memorize(msg, sig)
    47  	return sig, nil
    48  }
    49  
    50  // lookup looks up the given message in memory and returns
    51  // the signature, if the message is in memory
    52  func (ms *MemoizeSigner) lookup(msg []byte) ([]byte, bool) {
    53  	ms.RLock()
    54  	defer ms.RUnlock()
    55  	sig, exists := ms.memory[msgDigest(msg)]
    56  	return sig, exists
    57  }
    58  
    59  func (ms *MemoizeSigner) memorize(msg, signature []byte) {
    60  	if ms.maxEntries == 0 {
    61  		return
    62  	}
    63  	ms.RLock()
    64  	shouldShrink := len(ms.memory) >= (int)(ms.maxEntries)
    65  	ms.RUnlock()
    66  
    67  	if shouldShrink {
    68  		ms.shrinkMemory()
    69  	}
    70  	ms.Lock()
    71  	defer ms.Unlock()
    72  	ms.memory[msgDigest(msg)] = signature
    73  
    74  }
    75  
    76  // shrinkMemory evicts random messages from memory
    77  // until its size is smaller than maxEntries
    78  func (ms *MemoizeSigner) shrinkMemory() {
    79  	ms.Lock()
    80  	defer ms.Unlock()
    81  	for len(ms.memory) > (int)(ms.maxEntries) {
    82  		ms.evictFromMemory()
    83  	}
    84  }
    85  
    86  // evictFromMemory evicts a random message from memory
    87  func (ms *MemoizeSigner) evictFromMemory() {
    88  	for dig := range ms.memory {
    89  		delete(ms.memory, dig)
    90  		return
    91  	}
    92  }
    93  
    94  // msgDigest returns a digest of a given message
    95  func msgDigest(msg []byte) string {
    96  	return hex.EncodeToString(util.ComputeSHA256(msg))
    97  }