github.com/cloudflare/circl@v1.5.0/tss/rsa/signShare.go (about)

     1  package rsa
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"math"
     7  	"math/big"
     8  )
     9  
    10  // SignShare represents a portion of a signature. It is generated when a message is signed by a KeyShare. t SignShare's are then combined by calling CombineSignShares, where t is the Threshold.
    11  type SignShare struct {
    12  	xi *big.Int
    13  
    14  	Index uint
    15  
    16  	Players   uint
    17  	Threshold uint
    18  }
    19  
    20  func (s SignShare) String() string {
    21  	return fmt.Sprintf("(t,n): (%v,%v) index: %v xi: 0x%v",
    22  		s.Threshold, s.Players, s.Index, s.xi.Text(16))
    23  }
    24  
    25  // MarshalBinary encodes SignShare into a byte array in a format readable by UnmarshalBinary.
    26  // Note: Only Index's up to math.MaxUint16 are supported
    27  func (s *SignShare) MarshalBinary() ([]byte, error) {
    28  	// | Players: uint16 | Threshold: uint16 | Index: uint16 | xiLen: uint16 | xi: []byte |
    29  
    30  	if s.Players > math.MaxUint16 {
    31  		return nil, fmt.Errorf("rsa_threshold: signshare marshall: Players is too big to fit in a uint16")
    32  	}
    33  
    34  	if s.Threshold > math.MaxUint16 {
    35  		return nil, fmt.Errorf("rsa_threshold: signshare marshall: Threshold is too big to fit in a uint16")
    36  	}
    37  
    38  	if s.Index > math.MaxUint16 {
    39  		return nil, fmt.Errorf("rsa_threshold: signshare marshall: Index is too big to fit in a uint16")
    40  	}
    41  
    42  	players := uint16(s.Players)
    43  	threshold := uint16(s.Threshold)
    44  	index := uint16(s.Index)
    45  
    46  	xiBytes := s.xi.Bytes()
    47  	xiLen := len(xiBytes)
    48  
    49  	if xiLen > math.MaxInt16 {
    50  		return nil, fmt.Errorf("rsa_threshold: signshare marshall: xiBytes is too big to fit it's length in a uint16")
    51  	}
    52  
    53  	if xiLen == 0 {
    54  		xiLen = 1
    55  		xiBytes = []byte{0}
    56  	}
    57  
    58  	blen := 2 + 2 + 2 + 2 + xiLen
    59  	out := make([]byte, blen)
    60  
    61  	binary.BigEndian.PutUint16(out[0:2], players)
    62  	binary.BigEndian.PutUint16(out[2:4], threshold)
    63  	binary.BigEndian.PutUint16(out[4:6], index)
    64  
    65  	binary.BigEndian.PutUint16(out[6:8], uint16(xiLen))
    66  
    67  	copy(out[8:8+xiLen], xiBytes)
    68  
    69  	return out, nil
    70  }
    71  
    72  // UnmarshalBinary converts a byte array outputted from Marshall into a SignShare or returns an error if the value is invalid
    73  func (s *SignShare) UnmarshalBinary(data []byte) error {
    74  	// | Players: uint16 | Threshold: uint16 | Index: uint16 | xiLen: uint16 | xi: []byte |
    75  	if len(data) < 8 {
    76  		return fmt.Errorf("rsa_threshold: signshare unmarshalKeyShareTest failed: data length was too short for reading Players, Threshold, Index, and xiLen")
    77  	}
    78  
    79  	players := binary.BigEndian.Uint16(data[0:2])
    80  	threshold := binary.BigEndian.Uint16(data[2:4])
    81  	index := binary.BigEndian.Uint16(data[4:6])
    82  	xiLen := binary.BigEndian.Uint16(data[6:8])
    83  
    84  	if xiLen == 0 {
    85  		return fmt.Errorf("rsa_threshold: signshare unmarshalKeyShareTest failed: xi is a required field but xiLen was 0")
    86  	}
    87  
    88  	if uint16(len(data[8:])) < xiLen {
    89  		return fmt.Errorf("rsa_threshold: signshare unmarshalKeyShareTest failed: data length was too short for reading xi, needed: %d found: %d", xiLen, len(data[6:]))
    90  	}
    91  
    92  	xi := big.Int{}
    93  	bytes := make([]byte, xiLen)
    94  	copy(bytes, data[8:8+xiLen])
    95  	xi.SetBytes(bytes)
    96  
    97  	s.Players = uint(players)
    98  	s.Threshold = uint(threshold)
    99  	s.Index = uint(index)
   100  	s.xi = &xi
   101  
   102  	return nil
   103  }