Merge branch 'master' into interop

This commit is contained in:
Paul Hauner
2019-08-29 16:00:22 +10:00
53 changed files with 2513 additions and 1280 deletions

View File

@@ -5,7 +5,7 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
milagro_bls = { git = "https://github.com/sigp/milagro_bls", tag = "v0.9.0" }
milagro_bls = { git = "https://github.com/sigp/milagro_bls", tag = "v0.10.0" }
eth2_hashing = { path = "../eth2_hashing" }
hex = "0.3"
rand = "^0.5"

View File

@@ -1,5 +1,5 @@
use super::PublicKey;
use milagro_bls::AggregatePublicKey as RawAggregatePublicKey;
use milagro_bls::{AggregatePublicKey as RawAggregatePublicKey, G1Point};
/// A BLS aggregate public key.
///
@@ -13,15 +13,31 @@ impl AggregatePublicKey {
AggregatePublicKey(RawAggregatePublicKey::new())
}
pub fn add_without_affine(&mut self, public_key: &PublicKey) {
self.0.point.add(&public_key.as_raw().point)
}
pub fn affine(&mut self) {
self.0.point.affine()
}
pub fn add(&mut self, public_key: &PublicKey) {
self.0.add(public_key.as_raw())
}
pub fn add_point(&mut self, point: &G1Point) {
self.0.point.add(point)
}
/// Returns the underlying public key.
pub fn as_raw(&self) -> &RawAggregatePublicKey {
&self.0
}
pub fn into_raw(self) -> RawAggregatePublicKey {
self.0
}
/// Return a hex string representation of this key's bytes.
#[cfg(test)]
pub fn as_hex_string(&self) -> String {

View File

@@ -1,6 +1,7 @@
use super::*;
use milagro_bls::{
AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature,
G2Point,
};
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
@@ -76,13 +77,13 @@ impl AggregateSignature {
aggregate_public_keys.iter().map(|pk| pk.as_raw()).collect();
// Messages are concatenated into one long message.
let mut msg: Vec<u8> = vec![];
let mut msgs: Vec<Vec<u8>> = vec![];
for message in messages {
msg.extend_from_slice(message);
msgs.push(message.to_vec());
}
self.aggregate_signature
.verify_multiple(&msg[..], domain, &aggregate_public_keys[..])
.verify_multiple(&msgs, domain, &aggregate_public_keys[..])
}
/// Return AggregateSignature as bytes
@@ -112,6 +113,19 @@ impl AggregateSignature {
Ok(Self::empty_signature())
}
/// Returns the underlying signature.
pub fn as_raw(&self) -> &RawAggregateSignature {
&self.aggregate_signature
}
/// Returns the underlying signature.
pub fn from_point(point: G2Point) -> Self {
Self {
aggregate_signature: RawAggregateSignature { point },
is_empty: false,
}
}
/// Returns if the AggregateSignature `is_empty`
pub fn is_empty(&self) -> bool {
self.is_empty

View File

@@ -1,4 +1,5 @@
use super::{PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE};
use milagro_bls::G1Point;
/// A BLS aggregate public key.
///
@@ -7,6 +8,8 @@ use super::{PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE};
#[derive(Debug, Clone, Default)]
pub struct FakeAggregatePublicKey {
bytes: Vec<u8>,
/// Never used, only use for compatibility with "real" `AggregatePublicKey`.
pub point: G1Point,
}
impl FakeAggregatePublicKey {
@@ -14,10 +17,19 @@ impl FakeAggregatePublicKey {
Self::zero()
}
pub fn add_without_affine(&mut self, _public_key: &PublicKey) {
// No nothing.
}
pub fn affine(&mut self) {
// No nothing.
}
/// Creates a new all-zero's aggregate public key
pub fn zero() -> Self {
Self {
bytes: vec![0; BLS_PUBLIC_KEY_BYTE_SIZE],
point: G1Point::new(),
}
}
@@ -25,10 +37,18 @@ impl FakeAggregatePublicKey {
// No nothing.
}
pub fn as_raw(&self) -> &FakeAggregatePublicKey {
pub fn add_point(&mut self, _point: &G1Point) {
// No nothing.
}
pub fn as_raw(&self) -> &Self {
&self
}
pub fn into_raw(self) -> Self {
self
}
pub fn as_bytes(&self) -> Vec<u8> {
self.bytes.clone()
}

View File

@@ -2,6 +2,7 @@ use super::{
fake_aggregate_public_key::FakeAggregatePublicKey, fake_signature::FakeSignature,
BLS_AGG_SIG_BYTE_SIZE,
};
use milagro_bls::G2Point;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, PrefixedHexVisitor};
@@ -14,6 +15,8 @@ use ssz::{ssz_encode, Decode, DecodeError, Encode};
#[derive(Debug, PartialEq, Clone, Default, Eq)]
pub struct FakeAggregateSignature {
bytes: Vec<u8>,
/// Never used, only use for compatibility with "real" `AggregateSignature`.
pub point: G2Point,
}
impl FakeAggregateSignature {
@@ -26,9 +29,14 @@ impl FakeAggregateSignature {
pub fn zero() -> Self {
Self {
bytes: vec![0; BLS_AGG_SIG_BYTE_SIZE],
point: G2Point::new(),
}
}
pub fn as_raw(&self) -> &Self {
&self
}
/// Does glorious nothing.
pub fn add(&mut self, _signature: &FakeSignature) {
// Do nothing.
@@ -69,6 +77,7 @@ impl FakeAggregateSignature {
} else {
Ok(Self {
bytes: bytes.to_vec(),
point: G2Point::new(),
})
}
}

View File

@@ -1,4 +1,5 @@
use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE};
use milagro_bls::G1Point;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, HexVisitor};
@@ -14,6 +15,8 @@ use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Eq)]
pub struct FakePublicKey {
bytes: Vec<u8>,
/// Never used, only use for compatibility with "real" `PublicKey`.
pub point: G1Point,
}
impl FakePublicKey {
@@ -25,6 +28,7 @@ impl FakePublicKey {
pub fn zero() -> Self {
Self {
bytes: vec![0; BLS_PUBLIC_KEY_BYTE_SIZE],
point: G1Point::new(),
}
}
@@ -39,6 +43,7 @@ impl FakePublicKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
Ok(Self {
bytes: bytes.to_vec(),
point: G1Point::new(),
})
}
@@ -61,6 +66,13 @@ impl FakePublicKey {
hex_encode(end_bytes)
}
/// Returns the point as a hex string of the SSZ encoding.
///
/// Note: the string is prefixed with `0x`.
pub fn as_hex_string(&self) -> String {
hex_encode(self.as_ssz_bytes())
}
// Returns itself
pub fn as_raw(&self) -> &Self {
self

View File

@@ -1,5 +1,6 @@
use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE};
use hex::encode as hex_encode;
use milagro_bls::G2Point;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::HexVisitor;
@@ -13,6 +14,8 @@ use ssz::{ssz_encode, Decode, DecodeError, Encode};
pub struct FakeSignature {
bytes: Vec<u8>,
is_empty: bool,
/// Never used, only use for compatibility with "real" `Signature`.
pub point: G2Point,
}
impl FakeSignature {
@@ -26,6 +29,7 @@ impl FakeSignature {
Self {
bytes: vec![0; BLS_SIG_BYTE_SIZE],
is_empty: true,
point: G2Point::new(),
}
}
@@ -39,6 +43,10 @@ impl FakeSignature {
true
}
pub fn as_raw(&self) -> &Self {
&self
}
/// _Always_ returns true.
pub fn verify_hashed(
&self,
@@ -61,6 +69,7 @@ impl FakeSignature {
Ok(Self {
bytes: bytes.to_vec(),
is_empty,
point: G2Point::new(),
})
}
}

View File

@@ -7,12 +7,14 @@ mod keypair;
mod public_key_bytes;
mod secret_key;
mod signature_bytes;
mod signature_set;
pub use crate::keypair::Keypair;
pub use crate::public_key_bytes::PublicKeyBytes;
pub use crate::secret_key::SecretKey;
pub use crate::signature_bytes::SignatureBytes;
pub use milagro_bls::{compress_g2, hash_on_g2};
pub use milagro_bls::{compress_g2, hash_on_g2, G1Point};
pub use signature_set::{verify_signature_sets, SignatureSet, SignedMessage};
#[cfg(feature = "fake_crypto")]
mod fake_aggregate_public_key;

View File

@@ -28,7 +28,7 @@ impl PublicKey {
/// Returns the underlying point as compressed bytes.
///
/// Identical to `self.as_uncompressed_bytes()`.
fn as_bytes(&self) -> Vec<u8> {
pub fn as_bytes(&self) -> Vec<u8> {
self.as_raw().as_bytes()
}

View File

@@ -0,0 +1,193 @@
use crate::{AggregatePublicKey, AggregateSignature, PublicKey, Signature};
use milagro_bls::{G1Point, G2Point};
#[cfg(not(feature = "fake_crypto"))]
use milagro_bls::AggregateSignature as RawAggregateSignature;
type Message = Vec<u8>;
type Domain = u64;
#[derive(Clone)]
pub struct SignedMessage<'a> {
signing_keys: Vec<&'a G1Point>,
message: Message,
}
impl<'a> SignedMessage<'a> {
pub fn new<T>(signing_keys: Vec<&'a T>, message: Message) -> Self
where
T: G1Ref,
{
Self {
signing_keys: signing_keys.iter().map(|k| k.g1_ref()).collect(),
message,
}
}
}
#[derive(Clone)]
pub struct SignatureSet<'a> {
pub signature: &'a G2Point,
signed_messages: Vec<SignedMessage<'a>>,
domain: Domain,
}
impl<'a> SignatureSet<'a> {
pub fn single<S, T>(
signature: &'a S,
signing_key: &'a T,
message: Message,
domain: Domain,
) -> Self
where
T: G1Ref,
S: G2Ref,
{
Self {
signature: signature.g2_ref(),
signed_messages: vec![SignedMessage::new(vec![signing_key], message)],
domain,
}
}
pub fn dual<S, T>(
signature: &'a S,
message_0: Message,
message_0_signing_keys: Vec<&'a T>,
message_1: Message,
message_1_signing_keys: Vec<&'a T>,
domain: Domain,
) -> Self
where
T: G1Ref,
S: G2Ref,
{
Self {
signature: signature.g2_ref(),
signed_messages: vec![
SignedMessage::new(message_0_signing_keys, message_0),
SignedMessage::new(message_1_signing_keys, message_1),
],
domain,
}
}
pub fn new<S>(signature: &'a S, signed_messages: Vec<SignedMessage<'a>>, domain: Domain) -> Self
where
S: G2Ref,
{
Self {
signature: signature.g2_ref(),
signed_messages,
domain,
}
}
pub fn is_valid(&self) -> bool {
let sig = milagro_bls::AggregateSignature {
point: self.signature.clone(),
};
let mut messages: Vec<Vec<u8>> = vec![];
let mut pubkeys = vec![];
self.signed_messages.iter().for_each(|signed_message| {
messages.push(signed_message.message.clone());
let point = if signed_message.signing_keys.len() == 1 {
signed_message.signing_keys[0].clone()
} else {
aggregate_public_keys(&signed_message.signing_keys)
};
pubkeys.push(milagro_bls::AggregatePublicKey { point });
});
let pubkey_refs: Vec<&milagro_bls::AggregatePublicKey> =
pubkeys.iter().map(std::borrow::Borrow::borrow).collect();
sig.verify_multiple(&messages, self.domain, &pubkey_refs)
}
}
#[cfg(not(feature = "fake_crypto"))]
pub fn verify_signature_sets<'a>(iter: impl Iterator<Item = SignatureSet<'a>>) -> bool {
let rng = &mut rand::thread_rng();
RawAggregateSignature::verify_multiple_signatures(rng, iter.map(Into::into))
}
#[cfg(feature = "fake_crypto")]
pub fn verify_signature_sets<'a>(_iter: impl Iterator<Item = SignatureSet<'a>>) -> bool {
true
}
type VerifySet<'a> = (G2Point, Vec<G1Point>, Vec<Vec<u8>>, u64);
impl<'a> Into<VerifySet<'a>> for SignatureSet<'a> {
fn into(self) -> VerifySet<'a> {
let signature = self.signature.clone();
let (pubkeys, messages): (Vec<G1Point>, Vec<Message>) = self
.signed_messages
.into_iter()
.map(|signed_message| {
let key = if signed_message.signing_keys.len() == 1 {
signed_message.signing_keys[0].clone()
} else {
aggregate_public_keys(&signed_message.signing_keys)
};
(key, signed_message.message)
})
.unzip();
(signature, pubkeys, messages, self.domain)
}
}
/// Create an aggregate public key for a list of validators, failing if any key can't be found.
fn aggregate_public_keys<'a>(public_keys: &'a [&'a G1Point]) -> G1Point {
let mut aggregate =
public_keys
.iter()
.fold(AggregatePublicKey::new(), |mut aggregate, &pubkey| {
aggregate.add_point(pubkey);
aggregate
});
aggregate.affine();
aggregate.into_raw().point
}
pub trait G1Ref {
fn g1_ref(&self) -> &G1Point;
}
impl G1Ref for AggregatePublicKey {
fn g1_ref(&self) -> &G1Point {
&self.as_raw().point
}
}
impl G1Ref for PublicKey {
fn g1_ref(&self) -> &G1Point {
&self.as_raw().point
}
}
pub trait G2Ref {
fn g2_ref(&self) -> &G2Point;
}
impl G2Ref for AggregateSignature {
fn g2_ref(&self) -> &G2Point {
&self.as_raw().point
}
}
impl G2Ref for Signature {
fn g2_ref(&self) -> &G2Point {
&self.as_raw().point
}
}

View File

@@ -1,543 +1,3 @@
# simpleserialize (ssz) [WIP]
# simpleserialize (ssz)
This is currently a ***Work In Progress*** crate.
SimpleSerialize is a serialization protocol described by Vitalik Buterin. The
method is tentatively intended for use in the Ethereum Beacon Chain as
described in the [Ethereum 2.1 Spec](https://notes.ethereum.org/s/Syj3QZSxm).
The Beacon Chain specification is the core, canonical specification which we
are following.
The current reference implementation has been described in the [Beacon Chain
Repository](https://github.com/ethereum/beacon_chain/blob/master/ssz/ssz.py).
*Please Note: This implementation is presently a placeholder until the final
spec is decided.*\
*Do not rely upon it for reference.*
## Table of Contents
* [SimpleSerialize Overview](#simpleserialize-overview)
+ [Serialize/Encode](#serializeencode)
- [int or uint: 8/16/24/32/64/256](#int-or-uint-816243264256)
- [Address](#address)
- [Hash32](#hash32)
- [Bytes](#bytes)
- [List](#list)
+ [Deserialize/Decode](#deserializedecode)
- [Int or Uint: 8/16/24/32/64/256](#int-or-uint-816243264256)
- [Address](#address-1)
- [Hash32](#hash32-1)
- [Bytes](#bytes-1)
- [List](#list-1)
* [Technical Overview](#technical-overview)
* [Building](#building)
+ [Installing Rust](#installing-rust)
* [Dependencies](#dependencies)
+ [bytes v0.4.9](#bytes-v049)
+ [ethereum-types](#ethereum-types)
* [Interface](#interface)
+ [Encode](#encodable)
+ [Decode](#decodable)
+ [SszStream](#sszstream)
- [new()](#new)
- [append(&mut self, value: &E) -> &mut Self](#appendmut-self-value-e---mut-self)
- [append_encoded_val(&mut self, vec: &Vec)](#append_encoded_valmut-self-vec-vec)
- [append_vec(&mut self, vec: &Vec)](#append_vecmut-self-vec-vec)
- [drain(self) -> Vec](#drainself---vec)
+ [decode_ssz(ssz_bytes: &(u8), index: usize) -> Result](#decode_sszssz_bytes-u8-index-usize---resultt-usize-decodeerror)
+ [decode_ssz_list(ssz_bytes: &(u8), index: usize) -> Result, usize), DecodeError>](#decode_ssz_listssz_bytes-u8-index-usize---resultvec-usize-decodeerror)
+ [decode_length(bytes: &(u8), index: usize, length_bytes: usize) -> Result](#decode_lengthbytes-u8-index-usize-length_bytes-usize---resultusize-decodeerror)
* [Usage](#usage)
+ [Serializing/Encoding](#serializingencoding)
- [Rust](#rust)
* [Deserializing/Decoding](#deserializingdecoding)
- [Rust](#rust-1)
---
## SimpleSerialize Overview
The ``simpleserialize`` method for serialization follows simple byte conversion,
making it effective and efficient for encoding and decoding.
The decoding requires knowledge of the data **type** and the order of the
serialization.
Syntax:
| Shorthand | Meaning |
|:-------------|:----------------------------------------------------|
| `little` | ``little endian`` |
| `to_bytes` | convert to bytes. Params: ``(size, byte order)`` |
| `from_bytes` | convert from bytes. Params: ``(bytes, byte order)`` |
| `value` | the value to serialize |
| `rawbytes` | raw encoded/serialized bytes |
| `len(value)` | get the length of the value. (number of bytes etc) |
### Serialize/Encode
#### int or uint: 8/16/24/32/64/256
Convert directly to bytes the size of the int. (e.g. ``int16 = 2 bytes``)
All integers are serialized as **little endian**.
| Check to perform | Code |
|:-----------------------|:------------------------|
| Int size is not 0 | ``int_size > 0`` |
| Size is a byte integer | ``int_size % 8 == 0`` |
| Value is less than max | ``2**int_size > value`` |
```python
buffer_size = int_size / 8
return value.to_bytes(buffer_size, 'little')
```
#### Address
The address should already come as a hash/byte format. Ensure that length is
**20**.
| Check to perform | Code |
|:-----------------------|:---------------------|
| Length is correct (20) | ``len(value) == 20`` |
```python
assert( len(value) == 20 )
return value
```
#### Hash32
The hash32 should already be a 32 byte length serialized data format. The safety
check ensures the 32 byte length is satisfied.
| Check to perform | Code |
|:-----------------------|:---------------------|
| Length is correct (32) | ``len(value) == 32`` |
```python
assert( len(value) == 32 )
return value
```
#### Bytes
For general `byte` type:
1. Get the length/number of bytes; Encode into a 4 byte integer.
2. Append the value to the length and return: ``[ length_bytes ] + [
value_bytes ]``
```python
byte_length = (len(value)).to_bytes(4, 'little')
return byte_length + value
```
#### List
For lists of values, get the length of the list and then serialize the value
of each item in the list:
1. For each item in list:
1. serialize.
2. append to string.
2. Get size of serialized string. Encode into a 4 byte integer.
```python
serialized_list_string = ''
for item in value:
serialized_list_string += serialize(item)
serialized_len = len(serialized_list_string)
return serialized_len + serialized_list_string
```
### Deserialize/Decode
The decoding requires knowledge of the type of the item to be decoded. When
performing decoding on an entire serialized string, it also requires knowledge
of what order the objects have been serialized in.
Note: Each return will provide ``deserialized_object, new_index`` keeping track
of the new index.
At each step, the following checks should be made:
| Check Type | Check |
|:-------------------------|:----------------------------------------------------------|
| Ensure sufficient length | ``length(rawbytes) > current_index + deserialize_length`` |
#### Int or Uint: 8/16/24/32/64/256
Convert directly from bytes into integer utilising the number of bytes the same
size as the integer length. (e.g. ``int16 == 2 bytes``)
All integers are interpreted as **little endian**.
```python
byte_length = int_size / 8
new_index = current_index + int_size
return int.from_bytes(rawbytes[current_index:current_index+int_size], 'little'), new_index
```
#### Address
Return the 20 bytes.
```python
new_index = current_index + 20
return rawbytes[current_index:current_index+20], new_index
```
#### Hash32
Return the 32 bytes.
```python
new_index = current_index + 32
return rawbytes[current_index:current_index+32], new_index
```
#### Bytes
Get the length of the bytes, return the bytes.
```python
bytes_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little')
new_index = current_index + 4 + bytes_lenth
return rawbytes[current_index+4:current_index+4+bytes_length], new_index
```
#### List
Deserialize each object in the list.
1. Get the length of the serialized list.
2. Loop through deseralizing each item in the list until you reach the
entire length of the list.
| Check type | code |
|:------------------------------------|:--------------------------------------|
| rawbytes has enough left for length | ``len(rawbytes) > current_index + 4`` |
```python
total_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little')
new_index = current_index + 4 + total_length
item_index = current_index + 4
deserialized_list = []
while item_index < new_index:
object, item_index = deserialize(rawbytes, item_index, item_type)
deserialized_list.append(object)
return deserialized_list, new_index
```
## Technical Overview
The SimpleSerialize is a simple method for serializing objects for use in the
Ethereum beacon chain proposed by Vitalik Buterin. There are currently two
implementations denoting the functionality, the [Reference
Implementation](https://github.com/ethereum/beacon_chain/blob/master/ssz/ssz.py)
and the [Module](https://github.com/ethereum/research/tree/master/py_ssz) in
Ethereum research. It is being developed as a crate for the [**Rust programming
language**](https://www.rust-lang.org).
The crate will provide the functionality to serialize several types in
accordance with the spec and provide a serialized stream of bytes.
## Building
ssz currently builds on **rust v1.27.1**
### Installing Rust
The [**Rustup**](https://rustup.rs/) tool provides functionality to easily
manage rust on your local instance. It is a recommended method for installing
rust.
Installing on Linux or OSX:
```bash
curl https://sh.rustup.rs -sSf | sh
```
Installing on Windows:
* 32 Bit: [ https://win.rustup.rs/i686 ](https://win.rustup.rs/i686)
* 64 Bit: [ https://win.rustup.rs/x86_64 ](https://win.rustup.rs/x86_64)
## Dependencies
All dependencies are listed in the ``Cargo.toml`` file.
To build and install all related dependencies:
```bash
cargo build
```
### bytes v0.4.9
The `bytes` crate provides effective Byte Buffer implementations and
interfaces.
Documentation: [ https://docs.rs/bytes/0.4.9/bytes/ ](https://docs.rs/bytes/0.4.9/bytes/)
### ethereum-types
The `ethereum-types` provide primitives for types that are commonly used in the
ethereum protocol. This crate is provided by [Parity](https://www.parity.io/).
Github: [ https://github.com/paritytech/primitives ](https://github.com/paritytech/primitives)
---
## Interface
### Encode
A type is **Encode** if it has a valid ``ssz_append`` function. This is
used to ensure that the object/type can be serialized.
```rust
pub trait Encode {
fn ssz_append(&self, s: &mut SszStream);
}
```
### Decode
A type is **Decode** if it has a valid ``ssz_decode`` function. This is
used to ensure the object is deserializable.
```rust
pub trait Decode: Sized {
fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError>;
}
```
### SszStream
The main implementation is the `SszStream` struct. The struct contains a
buffer of bytes, a Vector of `uint8`.
#### new()
Create a new, empty instance of the SszStream.
**Example**
```rust
let mut ssz = SszStream::new()
```
#### append<E>(&mut self, value: &E) -> &mut Self
Appends a value that can be encoded into the stream.
| Parameter | Description |
|:---------:|:-----------------------------------------|
| ``value`` | Encode value to append to the stream. |
**Example**
```rust
ssz.append(&x)
```
#### append_encoded_val(&mut self, vec: &Vec<u8>)
Appends some ssz encoded bytes to the stream.
| Parameter | Description |
|:---------:|:----------------------------------|
| ``vec`` | A vector of serialized ssz bytes. |
**Example**
```rust
let mut a = [0, 1];
ssz.append_encoded_val(&a.to_vec());
```
#### append_vec<E>(&mut self, vec: &Vec<E>)
Appends some vector (list) of encodable values to the stream.
| Parameter | Description |
|:---------:|:----------------------------------------------|
| ``vec`` | Vector of Encode objects to be serialized. |
**Example**
```rust
ssz.append_vec(attestations);
```
#### drain(self) -> Vec<u8>
Consumes the ssz stream and returns the buffer of bytes.
**Example**
```rust
ssz.drain()
```
### decode_ssz<T>(ssz_bytes: &[u8], index: usize) -> Result<(T, usize), DecodeError>
Decodes a single ssz serialized value of type `T`. Note: `T` must be decodable.
| Parameter | Description |
|:-------------:|:------------------------------------|
| ``ssz_bytes`` | Serialized list of bytes. |
| ``index`` | Starting index to deserialize from. |
**Returns**
| Return Value | Description |
|:-------------------:|:----------------------------------------------|
| ``Tuple(T, usize)`` | Returns the tuple of the type and next index. |
| ``DecodeError`` | Error if the decoding could not be performed. |
**Example**
```rust
let res: Result<(u16, usize), DecodeError> = decode_ssz(&encoded_ssz, 0);
```
### decode_ssz_list<T>(ssz_bytes: &[u8], index: usize) -> Result<(Vec<T>, usize), DecodeError>
Decodes a list of serialized values into a vector.
| Parameter | Description |
|:-------------:|:------------------------------------|
| ``ssz_bytes`` | Serialized list of bytes. |
| ``index`` | Starting index to deserialize from. |
**Returns**
| Return Value | Description |
|:------------------------:|:----------------------------------------------|
| ``Tuple(Vec<T>, usize)`` | Returns the tuple of the type and next index. |
| ``DecodeError`` | Error if the decoding could not be performed. |
**Example**
```rust
let decoded: Result<(Vec<usize>, usize), DecodeError> = decode_ssz_list( &encoded_ssz, 0);
```
### decode_length(bytes: &[u8], index: usize, length_bytes: usize) -> Result<usize, DecodeError>
Deserializes the "length" value in the serialized bytes from the index. The
length of bytes is given (usually 4 stated in the reference implementation) and
is often the value appended to the list in front of the actual serialized
object.
| Parameter | Description |
|:----------------:|:-------------------------------------------|
| ``bytes`` | Serialized list of bytes. |
| ``index`` | Starting index to deserialize from. |
| ``length_bytes`` | Number of bytes to deserialize into usize. |
**Returns**
| Return Value | Description |
|:---------------:|:-----------------------------------------------------------|
| ``usize`` | The length of the serialized object following this length. |
| ``DecodeError`` | Error if the decoding could not be performed. |
**Example**
```rust
let length_of_serialized: Result<usize, DecodeError> = decode_length(&encoded, 0, 4);
```
---
## Usage
### Serializing/Encoding
#### Rust
Create the `simpleserialize` stream that will produce the serialized objects.
```rust
let mut ssz = SszStream::new();
```
Encode the values that you need by using the ``append(..)`` method on the `SszStream`.
The **append** function is how the value gets serialized.
```rust
let x: u64 = 1 << 32;
ssz.append(&x);
```
To get the serialized byte vector use ``drain()`` on the `SszStream`.
```rust
ssz.drain()
```
**Example**
```rust
// 1 << 32 = 4294967296;
// As bytes it should equal: [0,0,0,1,0,0,0]
let x: u64 = 1 << 32;
// Create the new ssz stream
let mut ssz = SszStream::new();
// Serialize x
ssz.append(&x);
// Check that it is correct.
assert_eq!(ssz.drain(), vec![0,0,0,1,0,0,0]);
```
## Deserializing/Decoding
#### Rust
From the `simpleserialize` bytes, we are converting to the object.
```rust
let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255];
// Returns the result and the next index to decode.
let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap();
// Check for correctness
// 2**64-1 = 18446744073709551615
assert_eq!(result, 18446744073709551615);
// Index = 3 (initial index) + 8 (8 byte int) = 11
assert_eq!(index, 11);
```
Decoding a list of items:
```rust
// Encoded/Serialized list with junk numbers at the front
let serialized_list = vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 32, 0, 0, 0,
0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0,
0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15];
// Returns the result (Vector of usize) and the index of the next
let decoded: (Vec<usize>, usize) = decode_ssz_list(&serialized_list, 10).unwrap();
// Check for correctness
assert_eq!(decoded.0, vec![15,15,15,15]);
assert_eq!(decoded.1, 46);
```
[<img src="https://img.shields.io/crates/v/eth2_ssz">](https://crates.io/crates/eth2_ssz)