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 //}