lnd.xprv/elkrem/serdes.go
Olaoluwa Osuntokun 5affed38fc
multi: update btcsuite API's to latest upstream changes
This commit makes a large number of minor changes concerning API usage
within the deamon to match the latest version on the upstream btcsuite
libraries.

The major changes are the switch from wire.ShaHash to chainhash.Hash,
and that wire.NewMsgTx() now takes a paramter indicating the version of
the transaction to be created.
2017-01-05 13:56:34 -08:00

131 lines
3.7 KiB
Go

package elkrem
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/roasbeef/btcd/chaincfg/chainhash"
)
/* Serialization and Deserialization methods for the Elkrem structs.
Senders turn into 41 byte long slices. Receivers are variable length,
with 41 bytes for each stored hash, up to a maximum of 48. Receivers are
prepended with the total number of hashes, so the total max size is 1969 bytes.
*/
// ToBytes turns the Elkrem Receiver into a bunch of bytes in a slice.
// first the number of nodes (1 byte), then a series of 41 byte long
// serialized nodes, which are 1 byte height, 8 byte index, 32 byte hash.
func (e *ElkremReceiver) ToBytes() ([]byte, error) {
numOfNodes := uint8(len(e.s))
// 0 element receiver also OK. Just an empty slice.
if numOfNodes == 0 {
return nil, nil
}
if numOfNodes > maxHeight+1 {
return nil, fmt.Errorf("Broken ElkremReceiver has %d nodes, max 64",
len(e.s))
}
var buf bytes.Buffer // create buffer
// write number of nodes (1 byte)
err := binary.Write(&buf, binary.BigEndian, numOfNodes)
if err != nil {
return nil, err
}
for _, node := range e.s {
// write 1 byte height
err = binary.Write(&buf, binary.BigEndian, node.h)
if err != nil {
return nil, err
}
// write 8 byte index
err = binary.Write(&buf, binary.BigEndian, node.i)
if err != nil {
return nil, err
}
if node.sha == nil {
return nil, fmt.Errorf("node %d has nil hash", node.i)
}
// write 32 byte sha hash
n, err := buf.Write(node.sha[:])
if err != nil {
return nil, err
}
if n != 32 { // make sure that was 32 bytes
return nil, fmt.Errorf("%d byte hash, expect 32", n)
}
}
if buf.Len() != (int(numOfNodes)*41)+1 {
return nil, fmt.Errorf("Somehow made wrong size buf, got %d expect %d",
buf.Len(), (numOfNodes*41)+1)
}
return buf.Bytes(), nil
}
func ElkremReceiverFromBytes(b []byte) (*ElkremReceiver, error) {
var e ElkremReceiver
if len(b) == 0 { // empty receiver, which is OK
return &e, nil
}
buf := bytes.NewBuffer(b)
// read 1 byte number of nodes stored in receiver
numOfNodes, err := buf.ReadByte()
if err != nil {
return nil, err
}
if numOfNodes < 1 || numOfNodes > maxHeight+1 {
return nil, fmt.Errorf("Read invalid number of nodes: %d", numOfNodes)
}
if buf.Len() != (int(numOfNodes) * 41) {
return nil, fmt.Errorf("Remaining buf wrong size, expect %d got %d",
(numOfNodes * 41), buf.Len())
}
e.s = make([]ElkremNode, numOfNodes)
for j, _ := range e.s {
e.s[j].sha = new(chainhash.Hash)
// read 1 byte height
err := binary.Read(buf, binary.BigEndian, &e.s[j].h)
if err != nil {
return nil, err
}
// read 8 byte index
err = binary.Read(buf, binary.BigEndian, &e.s[j].i)
if err != nil {
return nil, err
}
// read 32 byte sha hash
err = e.s[j].sha.SetBytes(buf.Next(32))
if err != nil {
return nil, err
}
// sanity check. Note that this doesn't check that index and height
// match. Could add that but it's slow.
if e.s[j].h > maxHeight { // check for super high nodes
return nil, fmt.Errorf("Read invalid node height %d", e.s[j].h)
}
if e.s[j].i > maxIndex { // check for index higher than height allows
return nil, fmt.Errorf("Node claims index %d; %d max at height %d",
e.s[j].i, maxIndex, e.s[j].h)
}
if j > 0 { // check that node heights are descending
if e.s[j-1].h < e.s[j].h {
return nil, fmt.Errorf("Node heights out of order")
}
}
}
return &e, nil
}
// ToBytes returns the root of the elkrem sender tree as a byte slice. This
// function is in place to allow one to export the root of the tree. However,
// node that if one uses a deterministic procedure to generate the root, then
// serialization isn't necessary as it can simply be re-derived on the fly.
func (e *ElkremSender) ToBytes() []byte {
return e.root[:]
}