use clap::{command, Args, Parser, Subcommand};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use patharg::{InputArg, OutputArg};
use primitive_types::H256;
use std::str::FromStr;
use crate::{
accumulators::AccumulatorType,
binary_tree::Height,
inclusion_proof,
percentage::{Percentage, ONE_HUNDRED_PERCENT},
InclusionProofFileType, MaxLiability, MaxThreadCount, Salt,
};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = MAIN_LONG_ABOUT)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
#[command(flatten)]
pub verbose: Verbosity<InfoLevel>,
}
#[derive(Debug, Subcommand)]
pub enum Command {
BuildTree {
#[command(subcommand)]
build_kind: BuildKindCommand,
#[arg(short, long, value_name = "ENTITY_IDS_FILE_PATH", global = true, long_help = GEN_PROOFS_HELP)]
gen_proofs: Option<InputArg>,
#[arg(short = 'S', long, value_name = "FILE_PATH", global = true, long_help = SERIALIZE_HELP)]
serialize: Option<OutputArg>,
#[arg(short, long, value_name = "DIR", global = true)]
root_serialize: Option<OutputArg>,
},
GenProofs {
#[arg(short, long)]
entity_ids: InputArg,
#[arg(short, long, value_name = "FILE_PATH")]
tree_file: InputArg,
#[arg(short, long, value_parser = Percentage::from_str, default_value = ONE_HUNDRED_PERCENT, value_name = "PERCENTAGE")]
range_proof_aggregation: Percentage,
#[arg(short, long, value_parser = InclusionProofFileType::from_str, default_value = InclusionProofFileType::default())]
file_type: inclusion_proof::InclusionProofFileType,
},
VerifyInclusionProof {
#[arg(short, long)]
file_path: InputArg,
#[arg(short, long, value_parser = H256::from_str, value_name = "BYTES")]
root_hash: H256,
#[arg(long, short, action)]
show_path: bool,
},
VerifyRoot {
#[arg(short, long)]
root_pub: InputArg,
#[arg(short, long)]
root_pvt: InputArg,
},
}
#[derive(Debug, Subcommand)]
pub enum BuildKindCommand {
New {
#[arg(short, long, value_enum, help = include_str!("./shared_docs/accumulator_type.md"))]
accumulator_type: AccumulatorType,
#[arg(long, value_parser = Salt::from_str, help = include_str!("./shared_docs/salt_b.md"))]
salt_b: Option<Salt>,
#[arg(long, value_parser = Salt::from_str, help = include_str!("./shared_docs/salt_s.md"))]
salt_s: Option<Salt>,
#[arg(long, value_parser = Height::from_str, default_value = Height::default(), value_name = "U8_INT", help = include_str!("./shared_docs/height.md"))]
height: Height,
#[arg(long, value_parser = MaxLiability::from_str, default_value = MaxLiability::default(), value_name = "U64_INT", help = include_str!("./shared_docs/max_liability.md"))]
max_liability: MaxLiability,
#[arg(long, value_parser = MaxThreadCount::from_str, default_value = MaxThreadCount::default(), value_name = "U8_INT", help = include_str!("./shared_docs/max_thread_count.md"))]
max_thread_count: MaxThreadCount,
#[arg(short, long, value_name = "FILE_PATH", long_help = SECRETS_HELP)]
secrets_file: InputArg,
#[command(flatten)]
entity_source: EntitySource,
},
#[command(about = COMMAND_CONFIG_FILE_ABOUT, long_about = COMMAND_CONFIG_FILE_LONG_ABOUT)]
ConfigFile {
file_path: InputArg,
},
Deserialize { path: InputArg },
}
#[derive(Args, Debug)]
#[group(required = true, multiple = false)]
pub struct EntitySource {
#[arg(short, long, value_name = "FILE_PATH", long_help = ENTITIES_FILE_HELP)]
pub entities_file: Option<InputArg>,
#[arg(short, long, value_name = "NUM_ENTITIES")]
pub random_entities: Option<u64>,
}
pub const MAIN_LONG_ABOUT: &str = "
DAPOL+ Proof of Liabilities protocol in Rust.
**NOTE** This project is currently still a work in progress, but is ready for
use as is. The code has _not_ been audited yet (as of Nov 2023).
DAPOL+ paper: https://eprint.iacr.org/2021/1350
Top-level doc for the project: https://hackmd.io/p0dy3R0RS5qpm3sX-_zreA
Source code: https://github.com/silversixpence-crypto/dapol/";
const GEN_PROOFS_HELP: &str = "
Generate inclusion proofs for the provided entity IDs, after building the tree.
The entity IDs file is expected to be a list of entity IDs, each on a new line.
All file formats are accepted. It is also possible to use the same entity IDs &
liabilities file that is accepted by the `entity-source` option in the
`build-tree new` command.
Custom configuration of the proofs is not supported here. The `gen-proofs`
command offers more options.";
const SERIALIZE_HELP: &str = "
Serialize the tree to a file. If the path given is a directory then a default
file name will be given. If the path given is a file then that file will be
overwritten (if it exists) or created (if it does not exist). The file
extension must be `.dapoltree`. The serialization option is ignored if
`build-tree deserialize` command is used.";
const SECRETS_HELP: &str = "
TOML file containing secrets. The file format is as follows:
```
master_secret = \"master_secret\"
```
All secrets should have at least 128-bit security, but need not be chosen from a
uniform distribution as they are passed through a key derivation function before
being used.";
const ENTITIES_FILE_HELP: &str = "
Path to file containing entity ID & liability entries (supported file
types: CSV).
CSV file format:
entity_id,liability";
const COMMAND_CONFIG_FILE_ABOUT: &str =
"Read tree configuration from a file. Supported file formats: TOML.";
const COMMAND_CONFIG_FILE_LONG_ABOUT: &str = concat!(
"
Read tree configuration from a file.
Supported file formats: TOML.
Config file format (TOML):
```
",
include_str!("../examples/dapol_config_example.toml"),
"
```"
);