github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/elkrem/serdes.go (about)

     1  package elkrem
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"github.com/mit-dci/lit/btcutil/chaincfg/chainhash"
     9  )
    10  
    11  /* Serialization and Deserialization methods for the Elkrem structs.
    12  Senders turn into 41 byte long slices.  Receivers are variable length,
    13  with 41 bytes for each stored hash, up to a maximum of 48.  Receivers are
    14  prepended with the total number of hashes, so the total max size is 1969 bytes.
    15  */
    16  
    17  // ToBytes turns the Elkrem Receiver into a bunch of bytes in a slice.
    18  // first the number of nodes (1 byte), then a series of 41 byte long
    19  // serialized nodes, which are 1 byte height, 8 byte index, 32 byte hash.
    20  func (e *ElkremReceiver) ToBytes() ([]byte, error) {
    21  	numOfNodes := uint8(len(e.Nodes))
    22  	// 0 element receiver also OK.  Just an empty slice.
    23  	if numOfNodes == 0 {
    24  		return nil, nil
    25  	}
    26  	if numOfNodes > maxHeight+1 {
    27  		return nil, fmt.Errorf("Broken ElkremReceiver has %d nodes, max 64",
    28  			len(e.Nodes))
    29  	}
    30  	var buf bytes.Buffer // create buffer
    31  
    32  	// write number of nodes (1 byte)
    33  	err := binary.Write(&buf, binary.BigEndian, numOfNodes)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	for _, node := range e.Nodes {
    38  		// write 1 byte height
    39  		err = binary.Write(&buf, binary.BigEndian, node.H)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		// write 8 byte index
    44  		err = binary.Write(&buf, binary.BigEndian, node.I)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		if node.Sha == nil {
    49  			return nil, fmt.Errorf("node %d has nil hash", node.I)
    50  		}
    51  		// write 32 byte sha hash
    52  		n, err := buf.Write(node.Sha.CloneBytes())
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		if n != 32 { // make sure that was 32 bytes
    57  			return nil, fmt.Errorf("%d byte hash, expect 32", n)
    58  		}
    59  	}
    60  	if buf.Len() != (int(numOfNodes)*41)+1 {
    61  		return nil, fmt.Errorf("Somehow made wrong size buf, got %d expect %d",
    62  			buf.Len(), (numOfNodes*41)+1)
    63  	}
    64  	return buf.Bytes(), nil
    65  }
    66  
    67  func ElkremReceiverFromBytes(b []byte) (*ElkremReceiver, error) {
    68  	var e ElkremReceiver
    69  	if len(b) == 0 { // empty receiver, which is OK
    70  		return &e, nil
    71  	}
    72  	buf := bytes.NewBuffer(b)
    73  	// read 1 byte number of nodes stored in receiver
    74  	numOfNodes, err := buf.ReadByte()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	if numOfNodes < 1 || numOfNodes > maxHeight+1 {
    79  		return nil, fmt.Errorf("Read invalid number of nodes: %d", numOfNodes)
    80  	}
    81  	if buf.Len() != (int(numOfNodes) * 41) {
    82  		return nil, fmt.Errorf("Remaining buf wrong size, expect %d got %d",
    83  			(numOfNodes * 41), buf.Len())
    84  	}
    85  
    86  	e.Nodes = make([]ElkremNode, numOfNodes)
    87  
    88  	for j, _ := range e.Nodes {
    89  		e.Nodes[j].Sha = new(chainhash.Hash)
    90  		// read 1 byte height
    91  		err := binary.Read(buf, binary.BigEndian, &e.Nodes[j].H)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		// read 8 byte index
    96  		err = binary.Read(buf, binary.BigEndian, &e.Nodes[j].I)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		// read 32 byte sha hash
   101  		err = e.Nodes[j].Sha.SetBytes(buf.Next(32))
   102  		if err != nil {
   103  			return nil, err
   104  		}
   105  		// sanity check.  Note that this doesn't check that index and height
   106  		// match.  Could add that but it's slow.
   107  		if e.Nodes[j].H > maxHeight { // check for super high nodes
   108  			return nil, fmt.Errorf("Read invalid node height %d", e.Nodes[j].H)
   109  		}
   110  		if e.Nodes[j].I > maxIndex { // check for index higher than height allows
   111  			return nil, fmt.Errorf("Node claims index %d; %d max at height %d",
   112  				e.Nodes[j].I, maxIndex, e.Nodes[j].H)
   113  		}
   114  
   115  		if j > 0 { // check that node heights are descending
   116  			if e.Nodes[j-1].H < e.Nodes[j].H {
   117  				return nil, fmt.Errorf("Node heights out of order")
   118  			}
   119  		}
   120  	}
   121  	return &e, nil
   122  }
   123  
   124  // There's no real point to the *sender* serialization because
   125  // you just make them from scratch each time.  Only thing to save
   126  // is the 32 byte seed and the current index.
   127  
   128  // ToBytes turns the Elkrem Sender into a 41 byte slice:
   129  // first the tree height (1 byte), then 8 byte index of last sent,
   130  // then the 32 byte root sha hash.
   131  //func (e *ElkremSender) ToBytes() ([]byte, error) {
   132  //	var buf bytes.Buffer
   133  //	// write 8 byte index of current sha (last sent)
   134  //	err := binary.Write(&buf, binary.BigEndian, e.current)
   135  //	if err != nil {
   136  //		return nil, err
   137  //	}
   138  //	// write 32 byte sha hash
   139  //	n, err := buf.Write(e.root.Bytes())
   140  //	if err != nil {
   141  //		return nil, err
   142  //	}
   143  //	if n != 32 {
   144  //		return nil, fmt.Errorf("%d byte hash, expect 32", n)
   145  //	}
   146  
   147  //	return buf.Bytes(), nil
   148  //}
   149  
   150  // ElkremSenderFromBytes turns a 41 byte slice into a sender, picking up at
   151  // the index where it left off.
   152  //func ElkremSenderFromBytes(b []byte) (ElkremSender, error) {
   153  //	var e ElkremSender
   154  //	e.root = new(wire.ShaHash)
   155  //	buf := bytes.NewBuffer(b)
   156  //	if buf.Len() != 40 {
   157  //		return e, fmt.Errorf("Got %d bytes for sender, expect 41")
   158  //	}
   159  //	// read 8 byte index
   160  //	err := binary.Read(buf, binary.BigEndian, &e.current)
   161  //	if err != nil {
   162  //		return e, err
   163  //	}
   164  //	// read 32 byte sha root
   165  //	err = e.root.SetBytes(buf.Next(32))
   166  //	if err != nil {
   167  //		return e, err
   168  //	}
   169  
   170  //	if e.current > maxIndex { // check for index higher than height allows
   171  //		return e, fmt.Errorf("Sender claims current %d; %d max with height %d",
   172  //			e.current, maxIndex, maxHeight)
   173  //	}
   174  //	return e, nil
   175  //}