sn_dbc 20.0.0

Safe Network DBC
Documentation
// Copyright 2023 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use crate::{
    rand::{distributions::Standard, Rng, RngCore},
    PublicKey,
};
use blsttc::{serde_impl::SerdeSecret, SecretKey, PK_SIZE};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// This is used to generate a new DbcId
/// from a PublicAddress, and the corresponding
/// DerivedKey from the MainKey of that PublicAddress.
pub type DerivationIndex = [u8; 32];

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct DbcId(PublicKey);

impl DbcId {
    pub fn new<G: Into<PublicKey>>(public_key: G) -> Self {
        Self(public_key.into())
    }

    pub fn to_bytes(&self) -> [u8; blsttc::PK_SIZE] {
        self.0.to_bytes()
    }

    /// Returns `true` if the signature matches the message.
    pub fn verify<M: AsRef<[u8]>>(&self, sig: &blsttc::Signature, msg: M) -> bool {
        self.0.verify(sig, msg)
    }
}

/// This is the key that unlocks the value of a Dbc.
/// Holding this key gives you access to the tokens of the
/// Dbc with the corresponding DbcId.
/// Like with the keys to your house or a safe, this is not something you share publicly.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct DerivedKey(SerdeSecret<SecretKey>);

impl DerivedKey {
    pub fn new<S: Into<SecretKey>>(secret_key: S) -> Self {
        Self(SerdeSecret(secret_key.into()))
    }

    /// This is the unique identifier of the Dbc that
    /// this instance of Dbc secret key unlocks.
    /// The Dbc does not exist until someone has sent tokens to it.
    pub fn dbc_id(&self) -> DbcId {
        DbcId(self.0.public_key())
    }

    pub(crate) fn sign(&self, msg: &[u8]) -> blsttc::Signature {
        self.0.sign(msg)
    }
}

/// This is a public address to which tokens can be sent.
/// The tokens will be sent via a unique Dbc.
///
/// When someone wants to send tokens to this PublicAddress,
/// they generate the id of the Dbc - the DbcId - that shall hold the tokens.
/// The DbcId is generated from this PublicAddress, and only the sender
/// will at this point know that the DbcId is related to this PublicAddress.
/// When creating the Dbc using that DbcId, the sender will also include the
/// DerivationIndex that was used to generate the DbcId, so that the recipient behind
/// the PublicAddress can also see that the DbcId is related to this PublicAddress.
/// The recipient can then use the received DerivationIndex to generate the DerivedKey
/// corresponding to that DbcId, and thus unlock the value of the Dbc by using that DerivedKey.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Clone)]
pub struct PublicAddress(pub PublicKey);

impl PublicAddress {
    pub fn new(public_key: PublicKey) -> Self {
        Self(public_key)
    }

    /// Verify that the signature is valid for the message.
    pub fn verify(&self, sig: &blsttc::Signature, msg: &[u8]) -> bool {
        self.0.verify(sig, msg)
    }

    /// Generate a new DbcId from provided DerivationIndex.
    /// This is supposed to be a unique identifier of a Dbc.
    /// A new Dbc id is generated by someone who wants to send tokens to the PublicAddress.
    /// When they create the new Dbc they will use this id, but that only works if this id was never used before.
    pub fn new_dbc_id(&self, index: &DerivationIndex) -> DbcId {
        DbcId(self.0.derive_child(index))
    }

    pub fn to_bytes(self) -> [u8; PK_SIZE] {
        self.0.to_bytes()
    }
}

/// A Dbc MainKey is held by anyone who wants to
/// send or receive tokens using Dbcs. It is held privately
/// and not shared with anyone.
///
/// The secret MainKey has a static PublicAddress, which
/// is shared with others in order to receive payments.
/// With this MainKey, new DerivedKey:DbcId pairs can be generated.
pub struct MainKey(SerdeSecret<SecretKey>);

impl MainKey {
    ///
    pub fn new(secret_key: SecretKey) -> Self {
        Self(SerdeSecret(secret_key))
    }

    /// Get the secret key.
    pub fn secret_key(&self) -> &SecretKey {
        &self.0
    }

    /// This is the static public address which is shared with others, and
    /// to which payments can be made by getting a new unique identifier for a Dbc to be created.
    pub fn public_address(&self) -> PublicAddress {
        PublicAddress(self.0.public_key())
    }

    /// Sign a message with the main key.
    pub fn sign(&self, msg: &[u8]) -> blsttc::Signature {
        self.0.sign(msg)
    }

    /// Derive the key - the DerivedKey - corresponding to a DbcId
    /// which was also derived using the same DerivationIndex.
    ///
    /// When someone wants to send tokens to the PublicAddress of this MainKey,
    /// they generate the id of the Dbc - the DbcId - that shall hold the tokens.
    /// The recipient of the tokens, is the person/entity that holds this MainKey.
    ///
    /// The created Dbc contains the derivation index that was used to
    /// generate that very DbcId.
    ///
    /// When passing the derivation index to this function (`fn derive_key`),
    /// a DerivedKey is generated corresponding to the DbcId. This DerivedKey can unlock the Dbc of that
    /// DbcId, thus giving access to the tokens it holds.
    /// By that, the recipient has received the tokens from the sender.
    pub fn derive_key(&self, index: &DerivationIndex) -> DerivedKey {
        DerivedKey::new(self.0.inner().derive_child(index))
    }

    /// Represent as bytes.
    pub fn to_bytes(&self) -> Vec<u8> {
        self.0.to_bytes().to_vec()
    }

    pub fn random() -> Self {
        Self::new(blsttc::SecretKey::random())
    }

    /// Create a randomly generated MainKey.
    pub fn random_from_rng(rng: &mut impl RngCore) -> Self {
        let sk: SecretKey = rng.sample(Standard);
        Self::new(sk)
    }

    pub fn random_derived_key(&self, rng: &mut impl RngCore) -> DerivedKey {
        self.derive_key(&random_derivation_index(rng))
    }
}

// generates a random derivation index
pub fn random_derivation_index(rng: &mut impl RngCore) -> [u8; 32] {
    let mut bytes = [0u8; 32];
    rng.fill_bytes(&mut bytes);
    bytes
}