Skip to content

Commit

Permalink
feat: add serde feature flag
Browse files Browse the repository at this point in the history
* reenable serde, now as feature flag 'serdes'
* consolidate blst types into blst.rs and make aliases
* make KeyImage a newtype around G1Affine, usable in a BTreeMap
* obtain AMT_SIZE and BF_SIZE constants from std::mem::size_of()
* make Dbc::owner() public api return blsttc::PublicKey instead of a G1Affine
* add private Dbc::owner_blst() convenience fn.
* remove unused DbcHelper
  • Loading branch information
dan-da authored and dirvine committed Feb 17, 2022
1 parent aa79a1e commit ff32395
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 225 deletions.
47 changes: 34 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,31 @@ edition = "2018"
[features]
dkg = [ "bls_dkg" ]

#-- Notes:
#-- 1. We want to be able to say cargo build --features serde
#-- 2. Feature name must be different from dependency name (or cargo gives error).
#-- 3. We must define serde feature explicitly in order to pass --features serde to crates we depend on.
#-- 4. Given 1-3, a solution *should* be to alias serde dep. (serde --> serdes) and change code refs.
#-- 5. However that results in Serialize macro "can't find crate" error.
#-- 6. So for now we give up and name this feature "serdes" instead.
# 7. But there is hope, because...
#-- 8. [2] is fixed with Namespaced Features in latest nightly. Once in stable,
#-- everything will work as desired.
#-- See: https://doc.rust-lang.org/cargo/reference/unstable.html#namespaced-features
#-- So this can change to:
#-- serde = ["dep:serde", ... ]
serdes = [
"serde",
"ringct-serde",
# "blsttc-serde",
]

ringct-serde = ["blst_ringct/serde"]
#blsttc-serde = ["blsttc/serde"]

[dependencies]
serde_json = "1.0.64"
thiserror = "1.0.24"
quickcheck = "1"
quickcheck = {git="https://github.com/davidrusu/quickcheck.git", branch="only-build-debug-reprs-on-failure"}
quickcheck_macros = "1"
rand = "0.7.1"
blst_ringct = {git="https://github.com/maidsafe/blst-ringct"}
Expand All @@ -40,30 +61,30 @@ xor_name = "3.1.0"
version = "2.0.0"
features = [ "sha3" ]

[dependencies.serde]
version = "1.0.111"
[dependencies.serde]
version = "1.0.133"
features = [ "derive", "rc" ]
optional = true

[dev-dependencies]
criterion = "0.3"
anyhow = "1.0.40"
serde = "1.0.126"
rand = "0.7.1"
rustyline = "8.0.0"
bincode = "1.3.3"

[dev-dependencies.sn_dbc]
path = "."
features = [ "dkg" ]
features = [ "dkg", "serdes" ]

[target."cfg(unix)".dev-dependencies]
termios = "0.3.3"

[[bench]]
name = "reissue"
harness = false
required-features = [ "dkg" ]
# [[bench]]
# name = "reissue"
# harness = false
# required-features = [ "dkg" ]

#[[example]]
#name = "mint-repl"
#path = "examples/mint-repl/mint-repl.rs"
# [[example]]
# name = "mint-repl"
# path = "examples/mint-repl/mint-repl.rs"
29 changes: 18 additions & 11 deletions src/amount_secrets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
// permissions and limitations relating to use of the SAFE Network Software.

use blst_ringct::RevealedCommitment;
use blstrs::Scalar;
use blsttc::{
Ciphertext, DecryptionShare, IntoFr, PublicKey, PublicKeySet, SecretKey, SecretKeySet,
SecretKeyShare,
Expand All @@ -17,20 +16,28 @@ use std::collections::BTreeMap;
use std::convert::Into;
use std::convert::TryFrom;

use crate::{Amount, Error};
use crate::{Amount, BlindingFactor, Error, SecretKeyBlst};

// note: Amount should move into blst_ringct crate.
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

// todo: Amount should probably move into blst_ringct crate.
// (or else blst_ringct::RevealedCommitment should be made generic over Amount type)

// note: AmountSecrets wraps RevealedCommitment to provide some methods
// for decrypting from Ciphertext using various blsttc components,
// eg SecretKey, SecretKeyShare, SecretKeySet, DecryptionShare
//
// Once blst_ringct uses blsttc, perhaps AmountSecrets can go away.
// todo: perhaps AmountSecrets should be renamed to be more consistent with
// RevealedCommitment, since it is just a NewType wrapper.
//
// Once blst_ringct uses blsttc, perhaps AmountSecrets functionality could
// move into RevealedCommitment, and AmountSecrets goes away entirely.

const AMT_SIZE: usize = 8; // Amount size: 8 bytes (u64)
const BF_SIZE: usize = 32; // Blinding factor size: 32 bytes (Scalar)
const AMT_SIZE: usize = std::mem::size_of::<Amount>(); // Amount size: 8 bytes (u64)
const BF_SIZE: usize = std::mem::size_of::<BlindingFactor>(); // Blinding factor size: 32 bytes (BlindingFactor)

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct AmountSecrets(RevealedCommitment);

Expand All @@ -39,7 +46,7 @@ impl AmountSecrets {
self.0.value
}

pub fn blinding_factor(&self) -> Scalar {
pub fn blinding_factor(&self) -> SecretKeyBlst {
self.0.blinding
}

Expand All @@ -56,7 +63,7 @@ impl AmountSecrets {
b
});
let mut b = [0u8; BF_SIZE];
let blinding_factor = Scalar::from_bytes_le({
let blinding_factor = BlindingFactor::from_bytes_le({
b.copy_from_slice(&bytes[AMT_SIZE..]);
&b
})
Expand All @@ -79,7 +86,7 @@ impl AmountSecrets {
b
});
let mut b = [0u8; BF_SIZE];
let blinding_factor = Scalar::from_bytes_le({
let blinding_factor = BlindingFactor::from_bytes_le({
b.copy_from_slice(&bytes[AMT_SIZE..]);
&b
})
Expand Down Expand Up @@ -107,9 +114,9 @@ impl From<RevealedCommitment> for AmountSecrets {
}
}

impl From<(Amount, Scalar)> for AmountSecrets {
impl From<(Amount, BlindingFactor)> for AmountSecrets {
/// create AmountSecrets from an amount and a randomly generated blinding factor
fn from(params: (Amount, Scalar)) -> Self {
fn from(params: (Amount, BlindingFactor)) -> Self {
let (value, blinding) = params;

Self(RevealedCommitment { value, blinding })
Expand Down
111 changes: 111 additions & 0 deletions src/blst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2021 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.

// This module defines blstrs aliases, wrappers, and helpers.
//
// blstrs types Scalar and G1Affine are used to represent distinct concepts
// in ringct such as:
// Scalar: SecretKey, BlindingFactor
// G1Affine: Commitment, PublicKey, KeyImage
//
// We provide type aliases to make the usage in each context clearer and to make the
// the sn_dbc public API simpler so that the caller should not need to depend on blstrs
// and use its types directly.
//
// Even sn_dbc uses the type aliases rather than directly using the blstrs types.
//
// We could consider moving some or all of this lower into blst_ringct to make these
// crates consistent.

use blstrs::{G1Affine, Scalar};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use blsttc::{PublicKey, SecretKey};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

pub type SecretKeyBlst = Scalar;
pub type PublicKeyBlst = G1Affine;
pub type Commitment = G1Affine;
pub type BlindingFactor = Scalar;

// We use a NewType wrapper for KeyImage because it needs to be used
// as a key in a BTreeMap.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Default)]
pub struct KeyImage(G1Affine);

impl PartialEq for KeyImage {
fn eq(&self, other: &Self) -> bool {
self.0.to_compressed() == other.0.to_compressed()
}
}

impl AsRef<G1Affine> for KeyImage {
fn as_ref(&self) -> &G1Affine {
&self.0
}
}

impl Eq for KeyImage {}

impl PartialOrd for KeyImage {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for KeyImage {
fn cmp(&self, other: &Self) -> Ordering {
self.0.to_compressed().cmp(&other.0.to_compressed())
}
}

impl Hash for KeyImage {
fn hash<H: Hasher>(&self, state: &mut H) {
let bytes = self.0.to_compressed();
bytes.hash(state);
}
}

impl From<G1Affine> for KeyImage {
fn from(k: G1Affine) -> Self {
Self(k)
}
}

// temporary: should go away once blsttc is integrated with with blstrs
pub struct BlsHelper {}

impl BlsHelper {
#[allow(dead_code)]
pub fn blsttc_to_blstrs_sk(sk: SecretKey) -> SecretKeyBlst {
let bytes = sk.to_bytes();
SecretKeyBlst::from_bytes_be(&bytes).unwrap()
}

pub fn blsttc_to_blstrs_pubkey(pk: &PublicKey) -> PublicKeyBlst {
let bytes = pk.to_bytes();
// fixme: unwrap
PublicKeyBlst::from_compressed(&bytes).unwrap()
}

pub fn blstrs_to_blsttc_pubkey(pk: &PublicKeyBlst) -> PublicKey {
let bytes = pk.to_compressed();
// fixme: unwrap
PublicKey::from_bytes(bytes).unwrap()
}

pub fn blstrs_to_blsttc_sk(sk: SecretKeyBlst) -> SecretKey {
let bytes = sk.to_bytes_be();
// fixme: unwrap
SecretKey::from_bytes(bytes).unwrap()
}
}
35 changes: 20 additions & 15 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use blst_ringct::ringct::{RingCtMaterial, RingCtTransaction};
pub use blst_ringct::{DecoyInput, MlsagMaterial, Output, RevealedCommitment, TrueInput};
use blstrs::group::Curve;
pub use blstrs::{G1Affine, Scalar};
use blsttc::{PublicKeySet, SignatureShare};
use bulletproofs::PedersenGens;
use rand_core::RngCore;
use std::collections::{BTreeMap, BTreeSet, HashSet};

use crate::{
Amount, AmountSecrets, Dbc, DbcContent, DerivedOwner, Error, KeyImage, NodeSignature,
ReissueRequest, ReissueShare, Result, SpentProof, SpentProofShare,
Amount, AmountSecrets, Commitment, Dbc, DbcContent, DerivedOwner, Error, KeyImage,
NodeSignature, PublicKeyBlst, ReissueRequest, ReissueShare, Result, SecretKeyBlst, SpentProof,
SpentProofShare,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

pub type OutputOwnerMap = BTreeMap<KeyImage, DerivedOwner>;

#[derive(Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default)]
pub struct TransactionBuilder {
material: RingCtMaterial,
output_owners: OutputOwnerMap,
Expand Down Expand Up @@ -56,7 +60,7 @@ impl TransactionBuilder {

pub fn add_input_by_secrets(
mut self,
secret_key: Scalar,
secret_key: SecretKeyBlst,
amount_secrets: AmountSecrets,
decoy_inputs: Vec<DecoyInput>,
mut rng: impl RngCore,
Expand All @@ -74,7 +78,7 @@ impl TransactionBuilder {

pub fn add_inputs_by_secrets(
mut self,
secrets: Vec<(Scalar, AmountSecrets, Vec<DecoyInput>)>,
secrets: Vec<(SecretKeyBlst, AmountSecrets, Vec<DecoyInput>)>,
mut rng: impl RngCore,
) -> Self {
for (secret_key, amount_secrets, decoy_inputs) in secrets.into_iter() {
Expand All @@ -84,8 +88,7 @@ impl TransactionBuilder {
}

pub fn add_output(mut self, output: Output, owner: DerivedOwner) -> Self {
self.output_owners
.insert(output.public_key().to_compressed(), owner);
self.output_owners.insert(output.public_key().into(), owner);
self.material.outputs.push(output);
self
}
Expand All @@ -100,7 +103,7 @@ impl TransactionBuilder {
self
}

pub fn input_owners(&self) -> Vec<blstrs::G1Affine> {
pub fn input_owners(&self) -> Vec<PublicKeyBlst> {
self.material.public_keys()
}

Expand Down Expand Up @@ -139,6 +142,7 @@ impl TransactionBuilder {

/// Builds a ReissueRequest from a RingCtTransaction and
/// any number of (input) DBC spent proof shares.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct ReissueRequestBuilder {
pub transaction: RingCtTransaction,
Expand Down Expand Up @@ -196,10 +200,10 @@ impl ReissueRequestBuilder {
.map(NodeSignature::threshold_crypto),
)?;

let public_commitments: Vec<G1Affine> = any_share.public_commitments.clone();
let public_commitments: Vec<Commitment> = any_share.public_commitments.clone();

let spent_proof = SpentProof {
key_image: any_share.key_image,
key_image: any_share.key_image.clone(),
spentbook_pub_key,
spentbook_sig,
public_commitments,
Expand All @@ -222,6 +226,7 @@ impl ReissueRequestBuilder {
/// A Builder for aggregating ReissueShare (Mint::reissue() results)
/// from multiple mint nodes and combining signatures to
/// generate the final Dbc outputs.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct DbcBuilder {
pub revealed_commitments: Vec<RevealedCommitment>,
Expand Down Expand Up @@ -292,7 +297,7 @@ impl DbcBuilder {
if !rs
.mint_node_signatures
.keys()
.any(|k| *k == mlsag.key_image.to_compressed())
.any(|k| *k == mlsag.key_image.into())
{
return Err(Error::ReissueShareMintNodeSignatureNotFoundForInput);
}
Expand Down Expand Up @@ -323,7 +328,7 @@ impl DbcBuilder {
let mint_sig = mint_public_key_set.combine_signatures(mint_sig_shares_ref)?;

let pc_gens = PedersenGens::default();
let output_commitments: Vec<(G1Affine, RevealedCommitment)> = self
let output_commitments: Vec<(Commitment, RevealedCommitment)> = self
.revealed_commitments
.iter()
.map(|r| (r.commit(&pc_gens).to_affine(), *r))
Expand All @@ -334,7 +339,7 @@ impl DbcBuilder {
.iter()
.map(|output| {
self.output_owners
.get(&output.public_key().to_compressed())
.get(&(*output.public_key()).into())
.ok_or(Error::PublicKeyNotFound)
})
.collect::<Result<_>>()?;
Expand Down Expand Up @@ -364,7 +369,7 @@ impl DbcBuilder {
.iter()
.map(|mlsag| {
(
mlsag.key_image.to_compressed(),
mlsag.key_image.into(),
(mint_public_key_set.public_key(), mint_sig.clone()),
)
})
Expand Down

0 comments on commit ff32395

Please sign in to comment.