github.com/amazechain/amc@v0.1.3/common/crypto/bls/signature_batch.go (about)

     1  package bls
     2  
     3  import "github.com/pkg/errors"
     4  
     5  // SignatureBatch refers to the defined set of
     6  // signatures and its respective public keys and
     7  // messages required to verify it.
     8  type SignatureBatch struct {
     9  	Signatures [][]byte
    10  	PublicKeys []PublicKey
    11  	Messages   [][32]byte
    12  }
    13  
    14  // NewSet constructs an empty signature batch object.
    15  func NewSet() *SignatureBatch {
    16  	return &SignatureBatch{
    17  		Signatures: [][]byte{},
    18  		PublicKeys: []PublicKey{},
    19  		Messages:   [][32]byte{},
    20  	}
    21  }
    22  
    23  // Join merges the provided signature batch to out current one.
    24  func (s *SignatureBatch) Join(set *SignatureBatch) *SignatureBatch {
    25  	s.Signatures = append(s.Signatures, set.Signatures...)
    26  	s.PublicKeys = append(s.PublicKeys, set.PublicKeys...)
    27  	s.Messages = append(s.Messages, set.Messages...)
    28  	return s
    29  }
    30  
    31  // Verify the current signature batch using the batch verify algorithm.
    32  func (s *SignatureBatch) Verify() (bool, error) {
    33  	return VerifyMultipleSignatures(s.Signatures, s.Messages, s.PublicKeys)
    34  }
    35  
    36  // Copy the attached signature batch and return it
    37  // to the caller.
    38  func (s *SignatureBatch) Copy() *SignatureBatch {
    39  	signatures := make([][]byte, len(s.Signatures))
    40  	pubkeys := make([]PublicKey, len(s.PublicKeys))
    41  	messages := make([][32]byte, len(s.Messages))
    42  	for i := range s.Signatures {
    43  		sig := make([]byte, len(s.Signatures[i]))
    44  		copy(sig, s.Signatures[i])
    45  		signatures[i] = sig
    46  	}
    47  	for i := range s.PublicKeys {
    48  		pubkeys[i] = s.PublicKeys[i].Copy()
    49  	}
    50  	for i := range s.Messages {
    51  		copy(messages[i][:], s.Messages[i][:])
    52  	}
    53  	return &SignatureBatch{
    54  		Signatures: signatures,
    55  		PublicKeys: pubkeys,
    56  		Messages:   messages,
    57  	}
    58  }
    59  
    60  // RemoveDuplicates removes duplicate signature sets from the signature batch.
    61  func (s *SignatureBatch) RemoveDuplicates() (int, *SignatureBatch, error) {
    62  	if len(s.Signatures) == 0 || len(s.PublicKeys) == 0 || len(s.Messages) == 0 {
    63  		return 0, s, nil
    64  	}
    65  	if len(s.Signatures) != len(s.PublicKeys) || len(s.Signatures) != len(s.Messages) {
    66  		return 0, s, errors.Errorf("mismatch number of signatures, publickeys and messages in signature batch. "+
    67  			"Signatures %d, Public Keys %d , Messages %d", s.Signatures, s.PublicKeys, s.Messages)
    68  	}
    69  	sigMap := make(map[string]int)
    70  	duplicateSet := make(map[int]bool)
    71  	for i := 0; i < len(s.Signatures); i++ {
    72  		if sigIdx, ok := sigMap[string(s.Signatures[i])]; ok {
    73  			if s.PublicKeys[sigIdx].Equals(s.PublicKeys[i]) &&
    74  				s.Messages[sigIdx] == s.Messages[i] {
    75  				duplicateSet[i] = true
    76  				continue
    77  			}
    78  		}
    79  		sigMap[string(s.Signatures[i])] = i
    80  	}
    81  
    82  	sigs := s.Signatures[:0]
    83  	pubs := s.PublicKeys[:0]
    84  	msgs := s.Messages[:0]
    85  
    86  	for i := 0; i < len(s.Signatures); i++ {
    87  		if duplicateSet[i] {
    88  			continue
    89  		}
    90  		sigs = append(sigs, s.Signatures[i])
    91  		pubs = append(pubs, s.PublicKeys[i])
    92  		msgs = append(msgs, s.Messages[i])
    93  	}
    94  
    95  	s.Signatures = sigs
    96  	s.PublicKeys = pubs
    97  	s.Messages = msgs
    98  
    99  	return len(duplicateSet), s, nil
   100  }
   101  
   102  // AggregateBatch aggregates common messages in the provided batch to
   103  // reduce the number of pairings required when we finally verify the
   104  // whole batch.
   105  func (s *SignatureBatch) AggregateBatch() (*SignatureBatch, error) {
   106  	if len(s.Signatures) == 0 || len(s.PublicKeys) == 0 || len(s.Messages) == 0 {
   107  		return s, nil
   108  	}
   109  	if len(s.Signatures) != len(s.PublicKeys) || len(s.Signatures) != len(s.Messages) {
   110  		return s, errors.Errorf("mismatch number of signatures, publickeys and messages in signature batch. "+
   111  			"Signatures %d, Public Keys %d , Messages %d", s.Signatures, s.PublicKeys, s.Messages)
   112  	}
   113  	msgMap := make(map[[32]byte]*SignatureBatch)
   114  
   115  	for i := 0; i < len(s.Messages); i++ {
   116  		currMsg := s.Messages[i]
   117  		currBatch, ok := msgMap[currMsg]
   118  		if ok {
   119  			currBatch.Signatures = append(currBatch.Signatures, s.Signatures[i])
   120  			currBatch.Messages = append(currBatch.Messages, s.Messages[i])
   121  			currBatch.PublicKeys = append(currBatch.PublicKeys, s.PublicKeys[i])
   122  			continue
   123  		}
   124  		currBatch = &SignatureBatch{
   125  			Signatures: [][]byte{s.Signatures[i]},
   126  			Messages:   [][32]byte{s.Messages[i]},
   127  			PublicKeys: []PublicKey{s.PublicKeys[i]},
   128  		}
   129  		msgMap[currMsg] = currBatch
   130  	}
   131  	newSt := NewSet()
   132  	for rt, b := range msgMap {
   133  		if len(b.PublicKeys) > 1 {
   134  			aggPub := AggregateMultiplePubkeys(b.PublicKeys)
   135  			aggSig, err := AggregateCompressedSignatures(b.Signatures)
   136  			if err != nil {
   137  				return nil, err
   138  			}
   139  			copiedRt := rt
   140  			b.PublicKeys = []PublicKey{aggPub}
   141  			b.Signatures = [][]byte{aggSig.Marshal()}
   142  			b.Messages = [][32]byte{copiedRt}
   143  		}
   144  		newObj := *b
   145  		newSt = newSt.Join(&newObj)
   146  	}
   147  	return newSt, nil
   148  }