This Repository provides the base API to open Channels, publish and receive signed data to the Tangle using the chrysalis-2
branch of iota-streams.
NOTE: async
version of IOTA-streams API has been used. In order to evaluate streams responses
,
tokio crate is needed (just like in the example).
This lib allows to :
- Create single branch channels
- Send signed packets public data to the Tangle (and the Tangle only).
- Each packet can be split in two parts:
- Public part that can be read from anyone who have access to channel.
- Masked part optionally encrypted with the Xchacha20-poly1305 authenticated encryption algorithm
- Restoring channels to keep chaining messages to an already existing channel, even after the application stops.
- Receive signed packets from a channel.
To learn more about IOTA-Streams click here
First, make sure to use the latest rust version using the command rustup update
.
To interact with Library implementations you can add the dependency in Cargo.toml
file:
[dependencies]
iota_streams_lib = { git = "https://github.com/lore-lml/iota-streams-lib.git"}
You can then import the library into your project with:
use iota_streams_lib::*;
let author = AuthorBuilder::new()
.node(node_url)
.send_options(send_opts)
.encoding(encoding)
.build();
node_url
is the url of a node on achrysalis
net.send_opts
is aSendOptions struct
of the official Iota-streams API.encoding
is the encoding method of data (i.e.utf-8
).- Each step of the building process is optional: default values for each field are provided.
let mut channel = ChannelWriter::new(author);
or directly using:
let mut channel = ChannelWriterBuilder::new()
.node(node_url)
.send_options(send_opts)
.encoding(encoding)
.build();
- The author is the one created above. It is suggested to use an author created from the
AuthorBuilder struct
to avoid unexpected behaviours.
let (channel_id, announce_id) = channel.open().await.unwrap();
This will open the Channel by generating the channel address and publishing the signature keys.
This address will be needed to read the data from the Tangle
async fn send_signed_raw_data(&mut self, p_data: Vec<u8>, m_data: Vec<u8>, key_nonce: Option<([u8;32], [u8;24])>) -> Result<String>
p_data:
it's a bytes vector containing the public part of the packet.m_data:
it's a bytes vector containing the masked part of the packet.key_nonce:
it's an optional tuple of fixed byte array containing theencryption key
andnonce
. This option enables the encryption with the given key and nonce for the masked part of the packet.
If the transaction is succesfully sent the id of the attached message will be returned.
async fn send_signed_packet<T>(&mut self, packet: &StreamsPacket<T>) -> Result<String>
- The type T needs to have the
StreamsPacketSerializer
trait. - For an easier use you can build a valid
StreamsPacket<T>
using aPacket
struct.
If the transaction is successfully sent the id of the attached message will be returned.
/* RawPacketBuilder to serialize and deserialize in bin format */
let packet = RawPacketBuilder::new()
.public(&p_data).unwrap()
.masked(&m_data).unwrap()
.key_nonce(key, nonce)
.build()
/* or JsonPacketBuilder to serialize and deserialize in json format */
let packet = JsonPacketBuilder::new()
...
.build()
let channel = ChannelWriter::new(author);
/* ********** Do stuff ********** */
channel.export_to_file(psw, file_path);
/* ********** applications stops ********** */
let channel = ChannelWriter::imports_from_file(file_path, psw, node_url, send_opts);
/* ********** Do stuff as the application never stops ********** */
psw
is the password you want to use to encrypt the channel state.file_path
is the path of the file that will be used to store the state.node_url
is anOption<&str>
: contains the specified url of the nodes as before orNone
for default value.send_opts
is anOption<SendOptions>
: contains the same struct as before orNone
for default value.
NOTE: Make sure to use the export_to_file()
method when you are sure the channel is updated to the last message attached to the tangle or the stored state will be inconsistent.
let subscriber = SubscriberBuilder::new()
.node(node_url)
.send_options(send_opts)
.encoding(encoding)
.build();
node_url
is the url of a node on achrysalis
net.send_opts
is aSendOptions struct
of the official Iota-streams API.encoding
is the encoding method of data (i.e.utf-8
).- Each step of the building process is optional: default values for each field are provided.
-
Create the reader:
let channel_reader = ChannelReader::new(subscriber, channel_id, announce_id);
or directly using:
let mut channel_reader = ChannelReaderBuilder::new() .node(node_url) .send_options(send_opts) .encoding(encoding) .build(channel_id, announce_id);
-
Attach the reader to the channel:
channel_reader.attach().await;
-
Retrieve all msgs on the channel:
let msgs = channel_reader.fetch_raw_msgs(key_nonce).await;
orlet msgs = channel_reader.fetch_parsed_msgs(key_nonce).await.unwrap();
-
Loop over them and parse.
-
creates a random seed of 81 chars.
fn random_seed() -> String
-
it creates the digest of a string using
fn hash_string(string: &str) -> String
blake2b
. -
it creates the official IOTA-streams
fn create_link(appinst: &str, msg_id: &str) -> Result<Address>
Address
struct with the specifiedappinst
andmsg_id
. -
it creates the corresponding key bytes array needed for the encryption and decryption of the masked part of the packet, starting from a secret string.
fn create_encryption_key(string_key: &str) -> [u8; 32]
-
it creates the corresponding nonce bytes array needed for the encryption and decryption of the masked part of the packet, starting from a secret string.
fn create_encryption_nonce(string_nonce: &str) -> [u8;24]
In the example
folder there is a more detailed example on how to send and receive packets to/from the tangle,
and recover channel state.
Use cargo run --package example
to run the example application.
In this lib an external approach for the encryption of the masked payload has been used.
IOTA-streams framework is currently in the alpha stage, so even if it should provide an internal protocol for key distribution and
a mechanism to send both public and masked data in the same packet, right now it has some limitations, and it's not easy to use.
Knowing this, you should use your own key distribution protocol in order to make subscribers able to
decrypt the encrypted data of a packet.