Francis Brunelle

SAFE: A Peer-to-Peer Data Storage Network

December 8, 2015

SAFE Network Montreal

A Peer-to-Peer Data Storage Network

What makes SAFE different?

1. Data security

     a) Logical (self-encryption)

       b) Physical (at least 4 online copies)

2. Autonomous network (close group consensus)

3. Self-authentication (PIN, keyword and password)

Mockups of SAFE Launcher

Launcher CLI with mock network

pub const XOR_NAME_LEN: usize = 64;

pub struct XorName(pub [u8; XOR_NAME_LEN]);

pub struct PublicId {
    public_encrypt_key: ::sodiumoxide::crypto::box_::PublicKey,
    public_sign_key: ::sodiumoxide::crypto::sign::PublicKey,
    name: ::XorName,
}


pub enum Data {
    StructuredData(StructuredData),
    ImmutableData(ImmutableData),
    PlainData(PlainData),
}

Routing DHT

pub struct PlainData {
    name: XorName,
    value: Vec<u8>,
}

pub struct XorName(pub [u8; XOR_NAME_LEN]);

Plain data

pub struct ImmutableData {
    type_tag: ImmutableDataType,
    value: Vec<u8>,
}

pub enum ImmutableDataType {
    Normal,
    Backup,
    Sacrificial,
}
pub fn name(&self) -> XorName {
    let digest = crypto::hash::sha512::hash(&self.value);
    match self.type_tag {
        ImmutableDataType::Normal => XorName(digest.0),
        ImmutableDataType::Backup => XorName(crypto::hash::sha512::hash(&digest.0).0),
        ImmutableDataType::Sacrificial => {
            XorName(crypto::hash::sha512::hash(&crypto::hash::sha512::hash(&digest.0).0).0)
        }
    }
}

Immutable data

pub struct StructuredData {
    type_tag: u64,
    identifier: ::XorName,
    data: Vec<u8>,
    previous_owner_keys: Vec<::sodiumoxide::crypto::sign::PublicKey>,
    version: u64,
    current_owner_keys: Vec<::sodiumoxide::crypto::sign::PublicKey>,
    previous_owner_signatures: Vec<::sodiumoxide::crypto::sign::Signature>,
}
pub fn compute_name(type_tag: u64, identifier: &::XorName) -> ::XorName {
    let type_tag_as_string = type_tag.to_string();

    let chain = identifier.0
                          .iter()
                          .cloned()
                          .chain(type_tag_as_string.as_bytes().iter().cloned())
                          .map(|a| a);

    ::XorName(::sodiumoxide::crypto::hash::sha512::hash(&chain.collect::<Vec<_>>()[..]).0)
}

Structured data

pub enum Address {
    Client(::sodiumoxide::crypto::sign::PublicKey),
    Node(::XorName),
}

pub enum DataRequest {
    StructuredData(XorName, u64),
    ImmutableData(XorName, ImmutableDataType),
    PlainData(XorName),
}

pub enum ExternalRequest {
    Get(::data::DataRequest, u8),
    Put(::data::Data),
    Post(::data::Data),
    Delete(::data::Data),
}
pub fn name(&self) -> XorName {
    match *self {
        DataRequest::StructuredData(ref name, tag) => StructuredData::compute_name(tag, name),
        DataRequest::ImmutableData(ref name, _) => name.clone(),
        DataRequest::PlainData(ref name) => name.clone(),
    }
}
pub struct FullId {
    public_id: ::PublicId,
    private_encrypt_key: ::sodiumoxide::crypto::box_::SecretKey,
    private_sign_key: ::sodiumoxide::crypto::sign::SecretKey,
}

enum State {
    Disconnected,
    Bootstrapping,
    Client,
    Node,
}

pub struct NodeInfo<T, U> {
    pub public_id: T,
    pub connections: Vec<U>,
}

pub struct RoutingTable<T, U> {
    nodes: Vec<NodeInfo<T, U>>,
    our_name: ::xor_name::XorName,
}

pub struct RoutingNode {
    client_restriction: bool,
    full_id: FullId,
    state: State,
    routing_table: RoutingTable<::id::PublicId, ::crust::Connection>,
    proxy_map: ::std::collections::HashMap<::crust::Connection, ::XorName>,
    client_map: ::std::collections::HashMap<crypto::sign::PublicKey, ::crust::Connection>,
}
pub enum Authority {
    ClientManager(XorName),
    NaeManager(XorName),
    NodeManager(XorName),
    ManagedNode(XorName),
    Client(XorName, crypto::sign::PublicKey),
}

pub enum Content {
    ExternalRequest(ExternalRequest),
    InternalRequest(InternalRequest),
    ExternalResponse(ExternalResponse),
    InternalResponse(InternalResponse),
}

pub enum Action {
    SendContent(::authority::Authority, ::authority::Authority, ::messages::Content),
    ClientSendContent(::authority::Authority, ::messages::Content),
    SetDataCacheOptions(::data_cache_options::DataCacheOptions),
    Terminate,
}
pub fn is_group(&self) -> bool {
    match *self {
        Authority::ClientManager(_) => true,
        Authority::NaeManager(_) => true,
        Authority::NodeManager(_) => true,
        Authority::ManagedNode(_) => false,
        Authority::Client(_, _) => false,
    }
}
pub struct DirectoryMetadata {
    key           : ::metadata::directory_key::DirectoryKey,
    name          : String,
    created_time  : ::time::Tm,
    modified_time : ::time::Tm,
    user_metadata : Vec<u8>,
    parent_dir_key: Option<::metadata::directory_key::DirectoryKey>,
}

pub struct DirectoryListing {
    metadata       : ::metadata::directory_metadata::DirectoryMetadata,
    sub_directories: Vec<::metadata::directory_metadata::DirectoryMetadata>,
    files          : Vec<::file::File>,
}

SAFE NFS (Network File System)

pub enum AccessLevel {
    Private,
    Public,
}

pub struct DirectoryKey {
    id          : ::xor_name::XorName,
    type_tag    : u64,
    versioned   : bool,
    access_level: ::AccessLevel,
}

pub struct DirectoryMetadata {
    key           : ::metadata::directory_key::DirectoryKey,
    name          : String,
    created_time  : ::time::Tm,
    modified_time : ::time::Tm,
    user_metadata : Vec<u8>,
    parent_dir_key: Option<::metadata::directory_key::DirectoryKey>,
}
pub struct FileMetadata {
    name         : String,
    size         : u64,
    created_time : ::time::Tm,
    modified_time: ::time::Tm,
    user_metadata: Vec<u8>,
}

pub struct ChunkDetails {
    pub chunk_num: u32,
    pub hash: Vec<u8>,
    pub pre_hash: Vec<u8>,
    pub source_size: u64,
}

pub enum DataMap {
    Chunks(Vec<ChunkDetails>),
    Content(Vec<u8>),
    None,
}

pub struct File {
    id      : ::xor_name::XorName,
    metadata: ::metadata::file_metadata::FileMetadata,
    datamap : ::self_encryption::datamap::DataMap,
}
pub struct DirectoryKey {
    id          : ::xor_name::XorName,
    type_tag    : u64,
    versioned   : bool,
    access_level: ::AccessLevel,
}

struct Dns {
    long_name     : String,
    services      : ::std::collections::HashMap<String,
                                                  ::safe_nfs::metadata::directory_key::DirectoryKey>,
    encryption_key: ::sodiumoxide::crypto::box_::PublicKey,
}

SAFE DNS (Decentralized Naming System)

pub struct Account {
    an_maid: ::id::RevocationIdType,
    maid: ::id::IdType,
    public_maid: ::id::PublicIdType,

    an_mpid: ::id::RevocationIdType,
    mpid: ::id::IdType,
    public_mpid: ::id::PublicIdType,

    user_root_dir_id: Option<::routing::NameType>,
    maidsafe_config_root_dir_id: Option<::routing::NameType>,
}

SAFE Core

pub struct Client {
    account            : Option<user_account::Account>,
    routing            : Routing,
    _raii_joiner       : ::utility::RAIIThreadJoiner,
    message_queue      : ::std::sync::Arc<::std::sync::Mutex<message_queue::MessageQueue>>,
    session_packet_id  : Option<::routing::NameType>,
    session_packet_keys: Option<SessionPacketEncryptionKeys>,
    client_manager_addr: Option<::routing::NameType>,
}
pub struct RevocationIdType {
    type_tags: (u64, u64, u64),
    public_key: ::sodiumoxide::crypto::sign::PublicKey,
    secret_key: ::sodiumoxide::crypto::sign::SecretKey,
}

pub struct IdType {
    type_tag   : u64,
    public_keys: (::sodiumoxide::crypto::sign::PublicKey, ::sodiumoxide::crypto::box_::PublicKey),
    secret_keys: (::sodiumoxide::crypto::sign::SecretKey, ::sodiumoxide::crypto::box_::SecretKey),
}

pub struct PublicIdType {
    type_tag: u64,
    public_keys: (::sodiumoxide::crypto::sign::PublicKey, ::sodiumoxide::crypto::box_::PublicKey),
    revocation_public_key: ::sodiumoxide::crypto::sign::PublicKey,
    signature: ::sodiumoxide::crypto::sign::Signature,
}

SAFE Launcher

pub struct LauncherConfiguration {
    pub app_id           : ::xor_name::XorName,
    pub app_name         : String,
    pub reference_count  : u32,
    pub app_root_dir_key : ::safe_nfs::metadata::directory_key::DirectoryKey,
    pub safe_drive_access: bool,
}

pub struct AppDetail {
    pub absolute_path    : String,
    pub safe_drive_access: bool,
}
pub struct ManagedApp {   
    pub id               : ::xor_name::XorName,
    pub name             : String,
    pub local_path       : Option<String>,
    pub reference_count  : u32,
    pub safe_drive_access: bool,
}

pub struct ModifyAppSettings {
    pub id               : ::routing::NameType,
    pub name             : Option<String>,
    pub local_path       : Option<String>,
    pub safe_drive_access: Option<bool>,
}
pub struct CreateDir {
    dir_path      : String,
    is_private    : bool,
    is_versioned  : bool,
    user_metadata : String,
    is_path_shared: bool,
}

pub struct CreateFile {
    file_path     : String,
    user_metadata : String,
    is_path_shared: bool,
}
pub struct GetDir {
    dir_path      : String,
    timeout_ms    : i64,
    is_path_shared: bool,
}
struct GetDirResponse {
    info           : DirectoryInfo,
    files          : Vec<FileInfo>,
    sub_directories: Vec<DirectoryInfo>,
}

struct DirectoryInfo {
    name                  : String,
    is_private            : bool,
    is_versioned          : bool,
    user_metadata         : String,
    creation_time_sec     : i64,
    creation_time_nsec    : i64,
    modification_time_sec : i64,
    modification_time_nsec: i64,
}

struct FileInfo {
    name                  : String,
    size                  : i64,
    user_metadata         : String,
    creation_time_sec     : i64,
    creation_time_nsec    : i64,
    modification_time_sec : i64,
    modification_time_nsec: i64,
}
pub struct GetFile {
    offset          : i64,
    length          : i64,
    file_path       : String,
    is_path_shared  : bool,
    include_metadata: bool,
}

struct GetFileResponse {
    content : String,
    metadata: Option<Metadata>,
}

struct Metadata {
    name                  : String,
    size                  : i64,
    user_metadata         : String,
    creation_time_sec     : i64,
    creation_time_nsec    : i64,
    modification_time_sec : i64,
    modification_time_nsec: i64,
}
struct OptionalParams {
    pub name         : Option<String>,
    pub user_metadata: Option<String>,
}

pub struct ModifyDir {
    dir_path      : String,
    new_values    : OptionalParams,
    is_path_shared: bool,
}
struct FileContentParams {
    pub bytes : String,
    pub offset: Option<u64>
}

struct OptionalParams {
    pub name         : Option<String>,
    pub content      : Option<FileContentParams>,
    pub user_metadata: Option<String>,
}

pub struct ModifyFile {
    file_path     : String,
    new_values    : OptionalParams,
    is_path_shared: bool,
}
pub struct DeleteDir {
    dir_path      : String,
    is_path_shared: bool,
}

pub struct DeleteFile {
    file_path     : String,
    is_path_shared: bool,
}
pub struct RegisterDns {
    pub long_name            : String,
    pub service_name         : String,
    pub is_path_shared       : bool,
    pub service_home_dir_path: String,
}

pub struct AddService {
    pub long_name            : String,
    pub service_name         : String,
    pub is_path_shared       : bool,
    pub service_home_dir_path: String,
}
struct HandshakeData {
    asymm_nonce    : String,
    asymm_pub_key  : String,
    launcher_string: String,
}

struct EcdhKeyExchgResponse {
    pub encrypted_symm_key : String,
    pub launcher_public_key: String,
}

Upcoming RFCs

  • MPID Messaging
  • Farm attempt
  • Safecoin implementation
  • Launcher data types API
  • Launcher DNS API
  • Vault config file
  • Crust refactor
  • Launcher authorisation - Registered and unregistered access