serialization / deserialization of elkrem built, untested
This commit is contained in:
parent
fc5e58ad7d
commit
a3f65bb4ad
@ -37,13 +37,13 @@ to compute a previous index, compute at most h hashes.
|
|||||||
// You can calculate h from i but I can't figure out how without taking
|
// You can calculate h from i but I can't figure out how without taking
|
||||||
// O(i) ops. Feels like there should be a clever O(h) way. 1 byte, whatever.
|
// O(i) ops. Feels like there should be a clever O(h) way. 1 byte, whatever.
|
||||||
type ElkremNode struct {
|
type ElkremNode struct {
|
||||||
i uint64 // index (ith node)
|
|
||||||
h uint8 // height of this node
|
h uint8 // height of this node
|
||||||
|
i uint64 // index (ith node)
|
||||||
sha *wire.ShaHash // hash
|
sha *wire.ShaHash // hash
|
||||||
}
|
}
|
||||||
type ElkremSender struct {
|
type ElkremSender struct {
|
||||||
current uint64 // last sent hash index
|
|
||||||
treeHeight uint8 // height of tree (size is 2**height -1 )
|
treeHeight uint8 // height of tree (size is 2**height -1 )
|
||||||
|
current uint64 // last sent hash index
|
||||||
maxIndex uint64 // top of the tree
|
maxIndex uint64 // top of the tree
|
||||||
root *wire.ShaHash // root hash of the tree
|
root *wire.ShaHash // root hash of the tree
|
||||||
}
|
}
|
||||||
|
245
elkrem/serdes.go
245
elkrem/serdes.go
@ -4,38 +4,31 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
//type ElkremNode struct {
|
/* Serialization and Deserialization methods for the Elkrem structs.
|
||||||
// i uint64 // index (ith node)
|
Senders turn into 41 byte long slices. Receivers are variable length,
|
||||||
// h uint8 // height of this node
|
with 41 bytes for each stored hash, up to a maximum of 64. Receivers are
|
||||||
// sha *wire.ShaHash // hash
|
prepended with the total number of hashes, so the total max size is 2625 bytes.
|
||||||
//}
|
*/
|
||||||
//type ElkremSender struct {
|
|
||||||
// current uint64 // last sent hash index
|
|
||||||
// treeHeight uint8 // height of tree (size is 2**height -1 )
|
|
||||||
// maxIndex uint64 // top of the tree
|
|
||||||
// root *wire.ShaHash // root hash of the tree
|
|
||||||
//}
|
|
||||||
//type ElkremReceiver struct {
|
|
||||||
// current uint64 // last received index (actually don't need it?)
|
|
||||||
// treeHeight uint8 // height of tree (size is 2**height -1 )
|
|
||||||
// s []ElkremNode // store of received hashes, max size = height
|
|
||||||
//}
|
|
||||||
|
|
||||||
// ToBytes turns an ElkremNode into a 41 byte long byte slice.
|
// ToBytes turns an ElkremNode into a 41 byte long byte slice.
|
||||||
// 8 byte index, 1 byte height, 32 byte hash
|
// 1 byte height, 8 byte index, 32 byte hash
|
||||||
func (e *ElkremNode) ToBytes() ([]byte, error) {
|
func (e *ElkremNode) ToBytes() ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
// write 1 byte height
|
||||||
err := binary.Write(&buf, binary.BigEndian, e.i)
|
err := binary.Write(&buf, binary.BigEndian, e.h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = binary.Write(&buf, binary.BigEndian, e.h)
|
// write 8 byte index
|
||||||
|
err = binary.Write(&buf, binary.BigEndian, e.i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// write 32 byte sha hash
|
||||||
n, err := buf.Write(e.sha.Bytes())
|
n, err := buf.Write(e.sha.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -47,26 +40,220 @@ func (e *ElkremNode) ToBytes() ([]byte, error) {
|
|||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromBytes turns an ElkremNode into a 41 byte long byte slice.
|
// ElkremNodeFromBytes turns a 41 byte long byte slice into an ElkremNode.
|
||||||
// 8 byte index, 1 byte height, 32 byte hash
|
// 1 byte height, 8 byte index, 32 byte hash.
|
||||||
|
func ElkremNodeFromBytes(b []byte) (ElkremNode, error) {
|
||||||
func ElkremNodeFromBytes([]byte) (ElkremNode, error) {
|
|
||||||
var e ElkremNode
|
var e ElkremNode
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
// read 1 byte height
|
||||||
|
err := binary.Read(buf, binary.BigEndian, &e.h)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 8 byte index
|
||||||
|
err = binary.Read(buf, binary.BigEndian, &e.i)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 32 byte sha hash
|
||||||
|
err = e.sha.SetBytes(buf.Next(32))
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// sanity check. Node that this doesn't check that index and height
|
||||||
|
// match. Could add that but it's slow.
|
||||||
|
if e.h > 63 { // check for super high nodes
|
||||||
|
return e, fmt.Errorf("Read invalid node height %d", e.h)
|
||||||
|
}
|
||||||
|
var max uint64 // maximum possible given height
|
||||||
|
for j := uint8(0); j <= e.h; j++ {
|
||||||
|
max = max<<1 | 1
|
||||||
|
}
|
||||||
|
if e.i > max-1 { // check for index higher than height allows
|
||||||
|
return e, fmt.Errorf("Node claims index %d; %d max at height %d",
|
||||||
|
e.i, max-1, e.h)
|
||||||
|
}
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToBytes turns the Elkrem Sender into a 41 byte slice:
|
||||||
|
// first the tree height (1 byte), then 8 byte index of last sent,
|
||||||
|
// then the 32 byte root sha hash.
|
||||||
func (e *ElkremSender) ToBytes() ([]byte, error) {
|
func (e *ElkremSender) ToBytes() ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
// write 1 byte height of tree (size of the whole sender)
|
||||||
|
err := binary.Write(&buf, binary.BigEndian, e.treeHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// write 8 byte index of current sha (last sent)
|
||||||
|
err = binary.Write(&buf, binary.BigEndian, e.current)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// write 32 byte sha hash
|
||||||
|
n, err := buf.Write(e.root.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n != 32 {
|
||||||
|
return nil, fmt.Errorf("%d byte hash, expect 32", n)
|
||||||
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ElkremSender) FromBytes([]byte) error {
|
// ElkremSenderFromBytes turns a 41 byte slice into a sender, picking up at
|
||||||
return nil
|
// the index where it left off.
|
||||||
|
func ElkremSenderFromBytes(b []byte) (ElkremSender, error) {
|
||||||
|
var e ElkremSender
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
// read 1 byte height
|
||||||
|
err := binary.Read(buf, binary.BigEndian, &e.treeHeight)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 8 byte index
|
||||||
|
err = binary.Read(buf, binary.BigEndian, &e.current)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 32 byte sha root
|
||||||
|
err = e.root.SetBytes(buf.Next(32))
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
if e.treeHeight < 1 || e.treeHeight > 63 { // check for super high / low tree
|
||||||
|
return e, fmt.Errorf("Read invalid sender tree height %d", e.treeHeight)
|
||||||
|
}
|
||||||
|
for j := uint8(0); j <= e.treeHeight; j++ {
|
||||||
|
e.maxIndex = e.maxIndex<<1 | 1
|
||||||
|
}
|
||||||
|
e.maxIndex--
|
||||||
|
|
||||||
|
if e.current > e.maxIndex { // check for index higher than height allows
|
||||||
|
return e, fmt.Errorf("Sender claims current %d; %d max with height %d",
|
||||||
|
e.current, e.maxIndex, e.treeHeight)
|
||||||
|
}
|
||||||
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToBytes turns the Elkrem Receiver into a bunch of bytes in a slice.
|
||||||
|
// first the tree height (1 byte), then 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) {
|
func (e *ElkremReceiver) ToBytes() ([]byte, error) {
|
||||||
return nil, nil
|
numOfNodes := uint8(len(e.s))
|
||||||
|
if numOfNodes == 0 {
|
||||||
|
return nil, fmt.Errorf("Can't serialize empty ElkremReceiver")
|
||||||
|
}
|
||||||
|
if numOfNodes > 64 {
|
||||||
|
return nil, fmt.Errorf("Broken ElkremReceiver has %d nodes, max 64",
|
||||||
|
len(e.s))
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer // create buffer
|
||||||
|
// write tree height (1 byte)
|
||||||
|
err := binary.Write(&buf, binary.BigEndian, e.treeHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
// write 32 byte sha hash
|
||||||
|
n, err := buf.Write(node.sha.Bytes())
|
||||||
|
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)+2 {
|
||||||
|
return nil, fmt.Errorf("Somehow made wrong size buf, got %d expect %d",
|
||||||
|
buf.Len(), (numOfNodes*41)+2)
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ElkremReceiver) FromBytes([]byte) error {
|
func ElkremReceiverFromBytes(b []byte) (ElkremReceiver, error) {
|
||||||
return nil
|
var e ElkremReceiver
|
||||||
|
var numOfNodes uint8
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
// read 1 byte tree height
|
||||||
|
err := binary.Read(buf, binary.BigEndian, &e.treeHeight)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
if e.treeHeight < 1 || e.treeHeight > 63 {
|
||||||
|
return e, fmt.Errorf("Read invalid receiver height: %d", e.treeHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
var max uint64 // maximum possible given height
|
||||||
|
for j := uint8(0); j <= e.treeHeight; j++ {
|
||||||
|
max = max<<1 | 1
|
||||||
|
}
|
||||||
|
max--
|
||||||
|
|
||||||
|
// read 1 byte number of nodes stored in receiver
|
||||||
|
err = binary.Read(buf, binary.BigEndian, &numOfNodes)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
if numOfNodes < 1 || numOfNodes > 64 {
|
||||||
|
return e, fmt.Errorf("Read invalid number of nodes: %d", numOfNodes)
|
||||||
|
}
|
||||||
|
if buf.Len() != (int(numOfNodes)*41)+2 {
|
||||||
|
return e, fmt.Errorf("Input buf wrong size, expect %d got %d",
|
||||||
|
(numOfNodes*41)+2, buf.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint8(0); i < numOfNodes; i++ {
|
||||||
|
var node ElkremNode
|
||||||
|
node.sha = new(wire.ShaHash)
|
||||||
|
// read 1 byte height
|
||||||
|
err := binary.Read(buf, binary.BigEndian, &node.h)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 8 byte index
|
||||||
|
err = binary.Read(buf, binary.BigEndian, &node.i)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// read 32 byte sha hash
|
||||||
|
err = node.sha.SetBytes(buf.Next(32))
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
// sanity check. Note that this doesn't check that index and height
|
||||||
|
// match. Could add that but it's slow.
|
||||||
|
if node.h > 63 { // check for super high nodes
|
||||||
|
return e, fmt.Errorf("Read invalid node height %d", node.h)
|
||||||
|
}
|
||||||
|
if node.i > max { // check for index higher than height allows
|
||||||
|
return e, fmt.Errorf("Node claims index %d; %d max at height %d",
|
||||||
|
node.i, max, node.h)
|
||||||
|
}
|
||||||
|
e.s = append(e.s, node)
|
||||||
|
if i > 0 { // check that node heights are descending
|
||||||
|
if e.s[i-1].h < e.s[i].h {
|
||||||
|
return e, fmt.Errorf("Node heights out of order")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user