├── src ├── events │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── utils │ ├── src │ │ ├── confgen │ │ │ ├── mod.rs │ │ │ └── cli.rs │ │ ├── thetacli │ │ │ ├── mod.rs │ │ │ └── cli.rs │ │ ├── client │ │ │ ├── mod.rs │ │ │ ├── cli.rs │ │ │ └── types.rs │ │ ├── server │ │ │ ├── mod.rs │ │ │ ├── cli.rs │ │ │ └── dirutil.rs │ │ └── lib.rs │ └── Cargo.toml ├── core │ ├── schemes │ │ ├── mcore │ │ │ ├── .gitignore │ │ │ ├── src │ │ │ │ ├── main.rs │ │ │ │ ├── rsa2048 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rsa.rs │ │ │ │ ├── rsa3072 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rsa.rs │ │ │ │ ├── rsa4096 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rsa.rs │ │ │ │ ├── arch.rs │ │ │ │ ├── ed25519 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rom.rs │ │ │ │ ├── secp256k1 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── rom.rs │ │ │ │ ├── bls12381 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── bls.rs │ │ │ │ ├── bn254 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── bls.rs │ │ │ │ ├── lib.rs │ │ │ │ └── rand.rs │ │ │ └── Cargo.toml │ │ ├── src │ │ │ ├── rsa_schemes │ │ │ │ ├── mod.rs │ │ │ │ ├── signatures │ │ │ │ │ └── mod.rs │ │ │ │ └── keygen.rs │ │ │ ├── dl_schemes │ │ │ │ ├── coins │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── bls04VRF.rs │ │ │ │ │ └── cks05_tests.rs │ │ │ │ ├── commitments │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── interface.rs │ │ │ │ │ ├── pedersen.rs │ │ │ │ │ └── pedersen_tests.rs │ │ │ │ ├── signatures │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── frost_tests.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── ciphers │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── benchmark_tests.rs │ │ │ │ ├── common_tests.rs │ │ │ │ └── common.rs │ │ │ ├── groups │ │ │ │ ├── ec │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── ed25519.rs │ │ │ │ │ ├── tests.rs │ │ │ │ │ ├── bn254.rs │ │ │ │ │ └── bls12381.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── simple_group_test.rs │ │ │ │ ├── group_generators.rs │ │ │ │ ├── group.rs │ │ │ │ └── group_tests.rs │ │ │ ├── integers │ │ │ │ ├── mod.rs │ │ │ │ ├── bigint_tests.rs │ │ │ │ └── sizedint_tests.rs │ │ │ ├── lib.rs │ │ │ ├── util.rs │ │ │ ├── readme.md │ │ │ ├── keys │ │ │ │ ├── mod.rs │ │ │ │ └── key_store_tests.rs │ │ │ ├── bin │ │ │ │ ├── group_generator.rs │ │ │ │ └── schemes_example.rs │ │ │ └── rand.rs │ │ ├── img │ │ │ └── schemes_reverse.png │ │ ├── derive │ │ │ ├── Cargo.toml │ │ │ └── readme.md │ │ └── Cargo.toml │ ├── orchestration │ │ ├── src │ │ │ ├── key_manager │ │ │ │ └── mod.rs │ │ │ ├── lib.rs │ │ │ ├── instance_manager │ │ │ │ ├── mod.rs │ │ │ │ └── instance.rs │ │ │ └── interface.rs │ │ └── Cargo.toml │ ├── protocols │ │ ├── src │ │ │ ├── threshold_coin │ │ │ │ ├── mod.rs │ │ │ │ ├── message_types.rs │ │ │ │ └── protocol.rs │ │ │ ├── threshold_cipher │ │ │ │ ├── mod.rs │ │ │ │ └── message_types.rs │ │ │ ├── threshold_signature │ │ │ │ ├── mod.rs │ │ │ │ └── message_types.rs │ │ │ ├── frost │ │ │ │ ├── mod.rs │ │ │ │ ├── message_types.rs │ │ │ │ └── tests.rs │ │ │ ├── lib.rs │ │ │ └── interface.rs │ │ ├── .rustc_info.json │ │ ├── Cargo.toml │ │ └── readme.md │ └── readme.md ├── network │ ├── src │ │ ├── proxy │ │ │ └── mod.rs │ │ ├── types │ │ │ ├── mod.rs │ │ │ ├── readme.md │ │ │ ├── config.rs │ │ │ └── message.rs │ │ ├── p2p │ │ │ └── mod.rs │ │ ├── network_manager │ │ │ ├── mod.rs │ │ │ ├── network_director.rs │ │ │ └── network_manager_builder.rs │ │ ├── lib.rs │ │ └── interface.rs │ ├── readme.md │ └── Cargo.toml ├── thetacrypt_blockchain_stub │ ├── src │ │ ├── lib.rs │ │ ├── cli │ │ │ ├── mod.rs │ │ │ ├── cli.rs │ │ │ └── types.rs │ │ └── bin │ │ │ └── client.rs │ ├── Cargo.toml │ └── readme.md ├── service │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── readme.md ├── .gitignore ├── proto │ ├── src │ │ ├── lib.rs │ │ ├── proxy_api.proto │ │ ├── scheme_types.proto │ │ └── protocol_types.proto │ ├── Cargo.toml │ └── build.rs ├── img │ └── thetacrypt-stack.png ├── log4rs.yaml ├── log4rs_to_file.yaml ├── setup.sh ├── Dockerfile ├── Cargo.toml └── bin │ └── key_example.rs ├── demo ├── server_ips.txt ├── Makefile ├── Dockerfile ├── docker-compose.yml └── readme.md ├── .dockerignore ├── .gitignore ├── .gitlab-ci.yml └── readme.md /src/events/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod event; 2 | -------------------------------------------------------------------------------- /src/utils/src/confgen/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; -------------------------------------------------------------------------------- /src/utils/src/thetacli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; -------------------------------------------------------------------------------- /src/core/schemes/mcore/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/network/src/proxy/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod proxyp2p; -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; -------------------------------------------------------------------------------- /src/service/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod rpc_request_handler; 2 | -------------------------------------------------------------------------------- /src/utils/src/client/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | pub mod types; -------------------------------------------------------------------------------- /src/network/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod message; 2 | pub mod config; -------------------------------------------------------------------------------- /src/core/orchestration/src/key_manager/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod key_manager; 2 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | conf/** 2 | target/** 3 | conf.tar.gz 4 | benchmark_conf/** 5 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/src/cli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | pub mod types; -------------------------------------------------------------------------------- /demo/server_ips.txt: -------------------------------------------------------------------------------- 1 | 192.167.20.2 2 | 192.167.20.3 3 | 192.167.20.4 4 | 192.167.20.5 -------------------------------------------------------------------------------- /src/network/src/p2p/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod p2p_component; 2 | pub mod p2p_component_tests; -------------------------------------------------------------------------------- /src/utils/src/server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod types; 2 | pub mod dirutil; 3 | pub mod cli; -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_coin/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod protocol; 2 | pub mod message_types; -------------------------------------------------------------------------------- /src/core/schemes/src/rsa_schemes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | 3 | pub mod signatures; 4 | -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_cipher/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod protocol; 2 | pub mod message_types; -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_signature/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod protocol; 2 | pub mod message_types; -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /src/proto/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod protocol_types; 2 | pub mod scheme_types; 3 | pub mod proxy_api; -------------------------------------------------------------------------------- /src/utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod confgen; 2 | pub mod client; 3 | pub mod thetacli; 4 | pub mod server; -------------------------------------------------------------------------------- /src/core/protocols/src/frost/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod message_types; 2 | pub mod protocol; 3 | pub mod tests; 4 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/coins/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cks05; 2 | #[cfg(test)] 3 | pub mod cks05_tests; 4 | -------------------------------------------------------------------------------- /src/core/orchestration/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod instance_manager; 2 | pub mod key_manager; 3 | pub mod interface; 4 | -------------------------------------------------------------------------------- /src/core/schemes/src/rsa_schemes/signatures/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sh00; 2 | #[cfg(test)] 3 | pub mod sh00_tests; 4 | -------------------------------------------------------------------------------- /src/img/thetacrypt-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptobern/thetacrypt/HEAD/src/img/thetacrypt-stack.png -------------------------------------------------------------------------------- /src/core/orchestration/src/instance_manager/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod instance; 2 | pub mod instance_manager; 3 | pub mod protocol_executor; 4 | -------------------------------------------------------------------------------- /src/network/src/network_manager/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod network_manager; 2 | pub mod network_manager_builder; 3 | pub mod network_director; -------------------------------------------------------------------------------- /src/core/schemes/img/schemes_reverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptobern/thetacrypt/HEAD/src/core/schemes/img/schemes_reverse.png -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/commitments/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interface; 2 | pub mod pedersen; 3 | #[cfg(test)] 4 | mod pedersen_tests; 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # We don't want to copy our target/ directory into the container, as that 2 | # would mess with cargo-chef. 3 | src/target/ 4 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/ec/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bls12381; 2 | pub mod bn254; 3 | pub mod ed25519; 4 | 5 | #[cfg(test)] 6 | pub mod tests; 7 | -------------------------------------------------------------------------------- /src/core/protocols/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod frost; 2 | pub mod interface; 3 | pub mod threshold_cipher; 4 | pub mod threshold_coin; 5 | pub mod threshold_signature; 6 | -------------------------------------------------------------------------------- /src/core/schemes/src/integers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bigint; 2 | #[cfg(test)] 3 | pub mod bigint_tests; 4 | pub mod sizedint; 5 | #[cfg(test)] 6 | pub mod sizedint_tests; 7 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/signatures/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bls04; 2 | #[cfg(test)] 3 | pub mod bls04_tests; 4 | pub mod frost; 5 | #[cfg(test)] 6 | pub mod frost_tests; 7 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ciphers; 2 | pub mod coins; 3 | pub mod commitments; 4 | pub mod common; 5 | #[cfg(test)] 6 | pub mod common_tests; 7 | pub mod signatures; 8 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ec; 2 | pub mod group; 3 | pub mod group_generators; 4 | 5 | #[cfg(test)] 6 | pub mod group_tests; 7 | 8 | #[cfg(test)] 9 | pub mod simple_group_test; 10 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/ciphers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bz03; 2 | //pub mod sg02; 3 | pub mod sg02; 4 | 5 | #[cfg(test)] 6 | mod bz03_tests; 7 | #[cfg(test)] 8 | mod sg02_tests; 9 | 10 | //mod benchmark_tests; 11 | -------------------------------------------------------------------------------- /src/log4rs.yaml: -------------------------------------------------------------------------------- 1 | appenders: 2 | console: 3 | kind: console 4 | encoder: 5 | pattern: "{d(%Y-%m-%d %H:%M:%S)} | {h({({l}):5.5})} | [{T}] {M}: {m}{n}" 6 | root: 7 | level: info 8 | appenders: 9 | - console -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | Cargo.lock 3 | */target/* 4 | src/conf/* 5 | *.DS_Store 6 | src/proto/src/*.rs 7 | src/protocols/conf/* 8 | */debug/* 9 | */.rustc_info.json 10 | */tmp/* 11 | src/start_network.sh 12 | src/log 13 | -------------------------------------------------------------------------------- /src/core/schemes/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod dl_schemes; 2 | pub mod groups; 3 | pub mod integers; 4 | pub mod interface; 5 | pub mod keys; 6 | pub mod rand; 7 | pub mod rsa_schemes; 8 | pub mod scheme_types_impl; 9 | pub mod util; 10 | const DEBUG: bool = true; 11 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mcore" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | [features] 11 | std = [] -------------------------------------------------------------------------------- /src/core/schemes/derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_derive" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | proc-macro = true 8 | name = "theta_derive" 9 | path = "src/lib.rs" 10 | 11 | [dependencies] 12 | syn = "0.15.23" 13 | quote = "0.6.10" 14 | -------------------------------------------------------------------------------- /src/proto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_proto" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | tonic = "0.8" 8 | prost = "0.11" 9 | serde = { version = "1.0", features = ["derive"] } 10 | 11 | [build-dependencies] 12 | tonic-build = "0.8" 13 | prost-build = "0.11.1" -------------------------------------------------------------------------------- /src/network/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod p2p; 2 | pub mod types; 3 | pub mod proxy; 4 | pub mod interface; 5 | pub mod network_manager; 6 | 7 | pub mod lib { 8 | use std::any::type_name; 9 | 10 | // get data type 11 | pub fn type_of(_: T) -> &'static str { 12 | type_name::() 13 | } 14 | } -------------------------------------------------------------------------------- /src/core/orchestration/src/interface.rs: -------------------------------------------------------------------------------- 1 | use tonic::async_trait; 2 | use theta_protocols::interface::ProtocolError; 3 | 4 | //Eventually this interface should be used by the executor. Add the terminate 5 | #[async_trait] 6 | pub trait ThresholdProtocol { 7 | async fn run(&mut self) -> Result, ProtocolError>; 8 | } -------------------------------------------------------------------------------- /src/core/schemes/src/groups/simple_group_test.rs: -------------------------------------------------------------------------------- 1 | use theta_proto::scheme_types::Group; 2 | 3 | use super::group::GroupElement; 4 | use crate::groups::group::GroupOperations; 5 | 6 | #[test] 7 | fn test_eq() { 8 | let a = GroupElement::new(&Group::Bls12381); 9 | let b = a.clone(); 10 | assert!(a == b); 11 | } 12 | -------------------------------------------------------------------------------- /src/core/protocols/.rustc_info.json: -------------------------------------------------------------------------------- 1 | {"rustc_fingerprint":13602171607366865355,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.67.1 (d5a82bbd2 2023-02-07)\nbinary: rustc\ncommit-hash: d5a82bbd26e1ad8b7401f6a718a9c57c96905483\ncommit-date: 2023-02-07\nhost: x86_64-unknown-linux-gnu\nrelease: 1.67.1\nLLVM version: 15.0.6\n","stderr":""}},"successes":{}} -------------------------------------------------------------------------------- /src/utils/src/client/cli.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Parser; 4 | 5 | /// CLI arguments of the server binary. 6 | #[derive(Parser, Debug)] 7 | #[command(about = format!("Server application {}", env!("CARGO_PKG_VERSION")))] 8 | pub struct ClientCli { 9 | #[arg(long, help = "Path to JSON-encoded configuration.")] 10 | pub config_file: PathBuf 11 | } 12 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/src/cli/cli.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Parser; 4 | 5 | /// CLI arguments of the server binary. 6 | #[derive(Parser, Debug)] 7 | #[command(about = format!("Server application {}", env!("CARGO_PKG_VERSION")))] 8 | pub struct P2PCli { 9 | #[arg(long, help = "Path to JSON-encoded configuration.")] 10 | pub config_file: PathBuf 11 | } -------------------------------------------------------------------------------- /src/utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utils" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde = { version = "1.0", features = ["derive", "std"] } 10 | serde_json = "1.0" 11 | clap = { version = "4.0.14", features = ["derive"] } 12 | log = "0.4.17" 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/log4rs_to_file.yaml: -------------------------------------------------------------------------------- 1 | appenders: 2 | console: 3 | kind: console 4 | encoder: 5 | pattern: "{d(%Y-%m-%d %H:%M:%S)} | {h({({l}):5.5})} | [{T}] {M}: {m}{n}" 6 | file: 7 | kind: file 8 | path: "/tmp/log/thetacrypt.log" 9 | encoder: 10 | pattern: "{d(%Y-%m-%d %H:%M:%S)} | {h({({l}):5.5})} | [{T}] {M}: {m}{n}" 11 | root: 12 | level: info 13 | appenders: 14 | - console 15 | - file -------------------------------------------------------------------------------- /src/events/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_events" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | chrono = { version = "0.4.31", features = ["serde"] } 10 | log = "0.4.17" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 14 | -------------------------------------------------------------------------------- /src/core/readme.md: -------------------------------------------------------------------------------- 1 | # The core layer 2 | 3 | The core layer represent the heart of the service. It is composed by three modules: 4 | 5 | - the **schemes module**: containing the implementation of the cryptographic primitives. 6 | - the **protocols module**: implementing the protocol logic for each different type of cryptosystem. 7 | - the **orchestration module**: managing concurrent protocol executions and handling the interaction with the other layers. 8 | 9 | For detailed information check out the README of every module. -------------------------------------------------------------------------------- /src/proto/build.rs: -------------------------------------------------------------------------------- 1 | fn main() -> Result<(), Box> { 2 | tonic_build::configure() 3 | .protoc_arg("--experimental_allow_proto3_optional") 4 | .out_dir("./src") 5 | .type_attribute("ThresholdScheme", "#[derive(serde::Serialize, serde::Deserialize)]") 6 | .type_attribute("Group", "#[derive(serde::Serialize, serde::Deserialize)]") 7 | .protoc_arg("--experimental_allow_proto3_optional") 8 | .compile(&["./src/protocol_types.proto","./src/scheme_types.proto", "./src/proxy_api.proto"], &["./src"])?; 9 | Ok(()) 10 | } -------------------------------------------------------------------------------- /src/proto/src/proxy_api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package proxy_api; 3 | 4 | service ProxyAPI { 5 | rpc forward_share(ForwardShareRequest) returns (ForwardShareResponse); 6 | rpc atomic_broadcast(AtomicBroadcastRequest) returns (AtomicBroadcastResponse); 7 | }; 8 | 9 | // See if we can add some sort of authentication 10 | message ForwardShareRequest { 11 | bytes data=1; 12 | }; 13 | 14 | message AtomicBroadcastRequest{ 15 | string id=1; 16 | bytes data=2; 17 | } 18 | 19 | message AtomicBroadcastResponse{}; 20 | message ForwardShareResponse {}; -------------------------------------------------------------------------------- /src/core/schemes/src/util.rs: -------------------------------------------------------------------------------- 1 | use log::info; 2 | 3 | /// print a vector of bytes to the console 4 | pub fn printbinary(array: &[u8], caption: Option<&str>) { 5 | if caption.is_some() { 6 | print!("{}", caption.unwrap()); 7 | } 8 | for i in 0..array.len() { 9 | print!("{:02X}", array[i]) 10 | } 11 | info!("") 12 | } 13 | 14 | 15 | /// convert a vector of bytes to an ASCII string 16 | pub fn hex2string(msg: &Vec) -> String { 17 | let mut res: String = String::new(); 18 | for i in 0..msg.len() { 19 | res.push(msg[i] as char); 20 | } 21 | 22 | res 23 | } -------------------------------------------------------------------------------- /src/network/src/interface.rs: -------------------------------------------------------------------------------- 1 | //T wil be NetMessage 2 | use tonic::async_trait; 3 | 4 | #[async_trait] 5 | pub trait Gossip: Send { 6 | type T; 7 | fn broadcast(&mut self, message: Self::T) -> Result<(), String>; 8 | async fn deliver(&mut self) -> Option; 9 | async fn init(&mut self) -> Result<(), String>; 10 | } 11 | 12 | #[async_trait] 13 | pub trait TOB: Send + Sync{ 14 | type T; 15 | fn broadcast(&mut self, message: Self::T); 16 | async fn deliver(&self) -> Self::T; 17 | } 18 | 19 | #[async_trait] 20 | pub trait NetworkService { 21 | fn listen_on(&self, port: i32); 22 | } -------------------------------------------------------------------------------- /src/core/schemes/src/groups/ec/ed25519.rs: -------------------------------------------------------------------------------- 1 | use crate::groups::group::GroupElement; 2 | use crate::integers::sizedint::{FixedSizeInt, SizedBigInt}; 3 | use crate::rand::RNG; 4 | use mcore::ed25519::{ 5 | big::{BIG, MODBYTES}, 6 | ecp::ECP, 7 | rom, 8 | }; 9 | use rasn::{AsnType, Decode, Encode, Encoder}; 10 | use theta_derive::{BigIntegerImpl, EcGroupImpl}; 11 | use theta_proto::scheme_types::{Group, ThresholdScheme}; 12 | 13 | #[derive(AsnType, Debug, EcGroupImpl)] 14 | pub struct Ed25519 { 15 | value: ECP, 16 | } 17 | 18 | #[derive(AsnType, Debug, BigIntegerImpl)] 19 | pub struct Ed25519BIG { 20 | value: BIG, 21 | } 22 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/src/bin/client.rs: -------------------------------------------------------------------------------- 1 | use theta_proto::proxy_api::{proxy_api_client::ProxyApiClient, ForwardShareRequest}; 2 | 3 | #[tokio::main] 4 | async fn main() -> Result<(), Box> { 5 | println!("Hello there! I'm the client!"); 6 | 7 | let mut client = ProxyApiClient::connect("http://localhost:30000").await?; 8 | 9 | let request = ForwardShareRequest{ 10 | data: "Hello World".to_owned().into_bytes(), 11 | }; 12 | 13 | let response = client.forward_share(request).await.expect("Client RPC request failed"); 14 | 15 | println!("RESPONSE={:?}", response); 16 | Ok(()) 17 | } -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/coins/bls04VRF.rs: -------------------------------------------------------------------------------- 1 | 2 | pub struct Bls04ThresholdVRF { 3 | pi: Bls04ThresholdSignature, 4 | vrf: GroupElement, // VRF output, result of an hash function to define 5 | } 6 | 7 | // See if we need to define new public keys or we can use bls04 existing ones 8 | 9 | #[derive(Clone, DlShare, PartialEq)] 10 | pub struct Bls04VRFShare { 11 | pi_i: Bls05SignatureShare, 12 | } 13 | 14 | impl Bls04VRFShare{ 15 | pub fn get_label(&self) -> &[u8] { 16 | self.pi_i.get_label() 17 | } 18 | 19 | pub fn get_scheme(&self) -> &ThresholdScheme { 20 | ThresholdScheme::Bls04VRF 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/utils/src/server/cli.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Parser; 4 | 5 | /// CLI arguments of the server binary. 6 | #[derive(Parser, Debug)] 7 | #[command(about = format!("Server application {}", env!("CARGO_PKG_VERSION")))] 8 | pub struct ServerCli { 9 | #[arg(long, help = "Path to JSON-encoded configuration.")] 10 | pub config_file: PathBuf, 11 | 12 | #[arg( 13 | long, 14 | help = "Path to log4rs configuration file.", 15 | default_value = "log4rs.yaml" 16 | )] 17 | pub log4rs_config: String, 18 | 19 | #[arg(long, help = "Path to JSON-encoded keystore.")] 20 | pub key_file: Option, 21 | } 22 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thetacrypt_blockchain_stub" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | theta_proto = {path = "../proto", version = "0.1.0"} 10 | 11 | tokio = { version = "1", features = ["full"] } 12 | tonic = "0.8" 13 | prost = "0.11" 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1.0" 16 | log = "0.4.17" 17 | log4rs = "1.1.1" 18 | env_logger = "0.9.1" 19 | clap = { version = "4.0.14", features = ["derive"] } 20 | 21 | [build-dependencies] 22 | tonic-build = "0.8" 23 | prost-build = "0.11.1" -------------------------------------------------------------------------------- /src/proto/src/scheme_types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package scheme_types; 3 | 4 | enum ThresholdScheme { 5 | Bz03 = 0; 6 | Sg02 = 1; 7 | Bls04 = 2; 8 | Cks05 = 3; 9 | Frost = 4; 10 | Sh00 = 5; 11 | } 12 | 13 | enum Group { 14 | Bls12381 = 0; 15 | Bn254 = 1; 16 | Ed25519 = 2; 17 | Rsa512 = 3; 18 | Rsa1024 = 4; 19 | Rsa2048 = 5; 20 | Rsa4096 = 6; 21 | } 22 | 23 | enum ThresholdOperation { 24 | Encryption = 0; 25 | Signature = 1; 26 | Coin = 2; 27 | } 28 | 29 | message PublicKeyEntry { 30 | string id = 1; 31 | scheme_types.ThresholdOperation operation = 2; 32 | scheme_types.ThresholdScheme scheme = 3; 33 | scheme_types.Group group = 4; 34 | bytes key = 5; 35 | } -------------------------------------------------------------------------------- /src/core/schemes/derive/readme.md: -------------------------------------------------------------------------------- 1 | ## Procedural Macros for ThetaCrypt Schemes 2 | 3 | This crate provides procedural macros that automate the implementation of elliptic curves and big integer wrappers. These wrappers provide an abstraction for the concrete underlying elliptic curve, such that schemes can be implemented in a curve-agnostic way. To reduce the amount of repeated code one has to write to add a new Miracl Core curve, this crate was created. 4 | 5 | ## Usage 6 | To create ECP and big integer implementations for a new curve, simply add the `#[derive()]` flag with the right macro identifier. 7 | 8 | #[derive(AsnType, Debug, EcGroupImpl)] 9 | pub struct Curve { 10 | value: ECP 11 | } 12 | 13 | #[derive(AsnType, Debug, BigIntegerImpl)] 14 | pub struct BigInt { 15 | value: BIG 16 | } -------------------------------------------------------------------------------- /src/core/schemes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_schemes" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | theta_proto = {path = "../../proto", version = "0.1.0"} 8 | 9 | time = "0.2.27" 10 | modular = "1.0.0" 11 | rug = "1.17.0" 12 | mcore = {path="mcore", version="0.1.0", features=["std"]} 13 | hex = "=0.3.0" 14 | rand = "0.8.5" 15 | chacha20poly1305 = "=0.9.0" 16 | rasn = "=0.6.1" 17 | gmp-mpfr-sys = "1.4" 18 | theta_derive = { path="derive", version = "0.1.0" } 19 | serde = { version = "1.0", features = ["derive"] } 20 | prost = "0.10" 21 | rand_chacha = "0.3.1" 22 | asn1 = "0.13.0" 23 | base64 = "0.21.5" 24 | log = "0.4.17" 25 | serde_json = "1.0" 26 | 27 | [lib] 28 | name = "theta_schemes" 29 | path = "src/lib.rs" 30 | 31 | [features] 32 | std = [] 33 | 34 | [build-dependencies] 35 | tonic-build = "0.7" -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa2048/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod dbig; 21 | pub mod ff; 22 | pub mod rsa; 23 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa3072/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod dbig; 21 | pub mod ff; 22 | pub mod rsa; 23 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa4096/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod dbig; 21 | pub mod ff; 22 | pub mod rsa; 23 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/arch.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | pub type Chunk = i64; 21 | pub type DChunk = i128; 22 | pub const CHUNK: usize = 64; 23 | -------------------------------------------------------------------------------- /src/core/schemes/src/readme.md: -------------------------------------------------------------------------------- 1 | ## ThetaCrypt - Schemes (src) 2 | The directory structure of this layer is as follows: 3 | 4 | - bin: contains a binary to generate generators for an elliptic curve group 5 | - dl_schemes: contains all discrete logarithm based schemes and groups 6 | - rsa_schemes: contains all schemes and groups based on the RSA problem 7 | - examples: contains examples on how to use the schemes layer 8 | 9 | Also, these are the most important files: 10 | - group.rs - provides the abstract Group enum to be used in schemes implementations 11 | - keys.rs - provides a wrapper and generator for the different keys 12 | - interface.rs - defines the main traits and structs for the schemes layer 13 | - rand.rs - contains pseudo-randomness generators (if you're not sure which one to use, it is recommended to use `RngAlgorithm::OsRng`) 14 | 15 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/ec/tests.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use theta_proto::scheme_types::Group; 3 | 4 | use crate::groups::group::GroupElement; 5 | use crate::integers::sizedint::SizedBigInt; 6 | use crate::rand::{RngAlgorithm, RNG}; 7 | 8 | use crate::groups::ec::bls12381::Bls12381; 9 | use crate::groups::group::GroupOperations; 10 | 11 | /* Test pow, mul, div */ 12 | fn op_test(group: &Group) { 13 | let x = GroupElement::new_rand(group, &mut RNG::new(RngAlgorithm::OsRng)); 14 | let y = x.pow(&SizedBigInt::new_int(group, 2)); 15 | let z = x.mul(&x); 16 | let w = z.div(&x); 17 | 18 | assert!(y.eq(&z)); 19 | assert!(w.eq(&x)); 20 | } 21 | 22 | #[test] 23 | fn test_bls12381() { 24 | op_test(&Group::Bls12381); 25 | } 26 | 27 | #[test] 28 | fn test_ed25519() { 29 | op_test(&Group::Ed25519); 30 | } 31 | 32 | #[test] 33 | fn test_bn254() { 34 | op_test(&Group::Bn254); 35 | } 36 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/ed25519/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod dbig; 21 | pub mod ecdh; 22 | pub mod hpke; 23 | pub mod ecp; 24 | pub mod fp; 25 | pub mod rom; 26 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/secp256k1/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod dbig; 21 | pub mod ecdh; 22 | pub mod hpke; 23 | pub mod ecp; 24 | pub mod fp; 25 | pub mod rom; 26 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/commitments/interface.rs: -------------------------------------------------------------------------------- 1 | use super::pedersen::{PedersenCommitment, PedersenCommitmentParams}; 2 | 3 | pub enum Commitment { 4 | Pedersen(PedersenCommitment), 5 | } 6 | 7 | pub enum CommitmentParams { 8 | Pedersen(PedersenCommitmentParams), 9 | } 10 | 11 | impl Commitment { 12 | pub fn commit(params: &CommitmentParams) -> Self { 13 | match params { 14 | CommitmentParams::Pedersen(pedersen_params) => { 15 | return Commitment::Pedersen(PedersenCommitment::commit(pedersen_params)); 16 | } 17 | } 18 | } 19 | 20 | pub fn verify(self, params: &CommitmentParams) -> bool { 21 | match self { 22 | Commitment::Pedersen(pedersen) => match params { 23 | CommitmentParams::Pedersen(pedersen_params) => { 24 | return pedersen.verify(pedersen_params); 25 | } 26 | }, 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/network/src/types/readme.md: -------------------------------------------------------------------------------- 1 | # Network Node 2 | 3 | A network node encapsulates the information needed for the replica connectivity towards other nodes running Thetacrypt. 4 | 5 | Because Thetacrypt implements two different configurations, the network node needs to distinguish between the case it needs 6 | a proxy node to simply delegate networking operation, or when it needs to know other peers because it is part of a peer-to-peer 7 | group. 8 | 9 | The `NetworkConfig` aims at specifying the details of the local node, and the information needed for the communication with 10 | other nodes. 11 | 12 | ``` 13 | pub struct NetworkConfig { 14 | pub local_peer: NetworkPeer, 15 | pub peers: Option>, 16 | pub proxy: Option, 17 | pub base_listen_address: String, 18 | } 19 | ``` 20 | 21 | Somewhere we also need to store the number of total nodes assumed in the network. 22 | 23 | N.B.: if we are working with the proxy we cannot count on knowing all the peers 24 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/bls12381/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod bls; 21 | pub mod dbig; 22 | pub mod ecp; 23 | pub mod ecp2; 24 | pub mod fp; 25 | pub mod fp12; 26 | pub mod fp2; 27 | pub mod fp4; 28 | pub mod mpin; 29 | pub mod pair; 30 | pub mod rom; -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/bn254/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | pub mod big; 20 | pub mod bls; 21 | pub mod dbig; 22 | pub mod ecp; 23 | pub mod ecp2; 24 | pub mod fp; 25 | pub mod fp12; 26 | pub mod fp2; 27 | pub mod fp4; 28 | pub mod mpin; 29 | pub mod pair; 30 | pub mod rom; 31 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/group_generators.rs: -------------------------------------------------------------------------------- 1 | // The values for the given constants were generated using the group_generators_generator binary 2 | // in the protocols binary directory. 3 | 4 | pub const BLS12381_ALTERNATE_GENERATOR_BYTES: [u8; 97] = [4, 21, 146, 60, 163, 4, 4, 97, 126, 80, 128, 110, 192, 21, 242, 89, 113, 87, 183, 93, 11, 211, 66, 239, 42, 95, 193, 203, 64, 65, 232, 154, 195, 86, 128, 111, 208, 76, 204, 11, 17, 140, 128, 63, 0, 6, 205, 148, 19, 21, 17, 242, 166, 187, 243, 246, 53, 97, 164, 29, 58, 73, 204, 255, 80, 223, 53, 185, 173, 17, 106, 197, 57, 209, 174, 189, 252, 56, 115, 174, 181, 246, 234, 172, 173, 176, 12, 75, 54, 239, 208, 0, 144, 75, 193, 40, 51]; 5 | 6 | pub const BN254_ALTERNATE_GENERATOR_BYTES: [u8; 65] = [4, 5, 104, 227, 186, 154, 221, 143, 179, 132, 36, 3, 255, 30, 125, 4, 174, 173, 190, 56, 153, 44, 44, 219, 58, 232, 245, 32, 57, 141, 251, 246, 3, 18, 21, 170, 161, 94, 130, 250, 252, 53, 34, 3, 77, 228, 243, 254, 60, 24, 7, 90, 254, 16, 154, 65, 59, 170, 252, 71, 87, 127, 118, 214, 64]; -------------------------------------------------------------------------------- /src/network/readme.md: -------------------------------------------------------------------------------- 1 | # Network layer 2 | 3 | The network layer aims at abstracting the communication from the rest of the codebase, providing precise interfaces. 4 | 5 | The entrypoint is the network manager, which takes care of orchestrating the processing of the incoming and outgoing messages. 6 | It also represents the connecting module with the protocol logic. 7 | 8 | The network manager exposes the interfaces of two main modules: one for peer-to-peer communication, which in the code base is referred to as a `Gossip` interface, and a total order broadcast module which is abbreviated with `TOB` for the interface name. 9 | 10 | In the case of the network layer too, the modular design allows for flexible integration of different communication solutions. 11 | 12 | The first entails the implementation of an ad-hoc networking layer realized through `libp2p`. `P2PComponent` under `p2p` in this code. 13 | 14 | The second considers integrating general proxy interfaces to delegate the networking functionality to an external platform. Under `proxy` in this code. 15 | -------------------------------------------------------------------------------- /demo/Makefile: -------------------------------------------------------------------------------- 1 | set-up: 2 | @if ! [ -d tmp ]; then mkdir tmp; fi 3 | @chmod -R 777 tmp 4 | @cp server_ips.txt tmp/server_ips.txt 5 | .PHONY: set-up 6 | 7 | build-docker: 8 | docker build -t rust-threshold-library -f Dockerfile .. 9 | .PHONY: build-docker 10 | 11 | config-files: 12 | @if ! [ -f ./conf/node0.keystore ]; then docker run --rm -v $(CURDIR)/tmp:/target/release/conf:Z rust-threshold-library ./thetacli keygen -k=3 -n=4 --subjects all --output ./conf --new; fi 13 | @if ! [ -f ./conf/server_0.json ]; then docker run --rm -v $(CURDIR)/tmp:/target/release/conf:Z rust-threshold-library ./confgen --ip-file=conf/server_ips.txt --outdir=conf; fi # the outdir here is created under protocols 14 | .PHONY: config-files 15 | 16 | demo-start: 17 | docker-compose up 18 | .PHONY: demo-start 19 | 20 | client-start: 21 | docker run -it -v $(CURDIR)/tmp:/target/release/conf:Z --net threshold-net rust-threshold-library ./client --config-file=conf/client.json 22 | .PHONY: client-start 23 | 24 | demo-stop: 25 | docker-compose down 26 | .PHONY: demo-stop 27 | 28 | clean-up: demo-stop 29 | @rm -r tmp 30 | .PHONY: clean-up 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/ec/bn254.rs: -------------------------------------------------------------------------------- 1 | use std::mem::ManuallyDrop; 2 | 3 | use crate::integers::sizedint::{FixedSizeInt, SizedBigInt}; 4 | use crate::{interface::SchemeError, rand::RNG}; 5 | use mcore::bn254::{ 6 | big::{BIG, MODBYTES}, 7 | ecp::ECP, 8 | ecp2::ECP2, 9 | fp12::FP12, 10 | pair, rom, 11 | }; 12 | use rasn::{AsnType, Decode, Encode, Encoder}; 13 | use theta_derive::{BigIntegerImpl, EcPairingGroupImpl}; 14 | use theta_proto::scheme_types::{Group, ThresholdScheme}; 15 | 16 | use crate::groups::group::GroupElement; 17 | 18 | #[repr(C)] 19 | union ECPoint { 20 | ecp: ManuallyDrop, 21 | ecp2: ManuallyDrop, 22 | fp12: ManuallyDrop, 23 | } 24 | 25 | impl std::fmt::Debug for ECPoint { 26 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 27 | write!(f, "") 28 | } 29 | } 30 | 31 | #[derive(Debug, EcPairingGroupImpl)] 32 | pub struct Bn254 { 33 | i: u8, /* i indicates whether element is ECP, ECP2 or FP12 */ 34 | value: ECPoint, 35 | } 36 | 37 | #[derive(Debug, AsnType, BigIntegerImpl)] 38 | pub struct Bn254BIG { 39 | value: BIG, 40 | } 41 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | docker-build: 2 | stage: build 3 | 4 | tags: 5 | - has-docker-access 6 | 7 | before_script: 8 | - docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" 9 | 10 | script: 11 | - cd src 12 | # We create two images, one tagged with the (short) commit ID, one with the sanitized branch name. 13 | - commit_image="${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}" 14 | - branch_image="${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}" 15 | 16 | - docker build --pull -t "${commit_image}" . 17 | - docker tag "${commit_image}" "${branch_image}" 18 | - docker push "${commit_image}" 19 | - docker push "${branch_image}" 20 | 21 | 22 | test: 23 | stage: test 24 | 25 | image: rust:1.81 26 | 27 | script: 28 | - apt-get update && apt-get install -yqq build-essential cmake protobuf-compiler 29 | - cd src 30 | - cargo check --workspace 31 | - cargo build --workspace 32 | # We skip the two 'unit tests' which require a local setup to be running to pass. 33 | - cargo test --workspace --no-fail-fast -- --skip test_local_servers --skip test_local_servers_backlog 34 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/ec/bls12381.rs: -------------------------------------------------------------------------------- 1 | use crate::groups::group::GroupElement; 2 | use crate::integers::sizedint::{FixedSizeInt, SizedBigInt}; 3 | use crate::{interface::SchemeError, rand::RNG}; 4 | use mcore::bls12381::{ 5 | big::{BIG, MODBYTES}, 6 | ecp::ECP, 7 | ecp2::ECP2, 8 | fp12::FP12, 9 | pair, rom, 10 | }; 11 | use rasn::{AsnType, Decode, Encode, Encoder}; 12 | use std::mem::ManuallyDrop; 13 | use theta_derive::{BigIntegerImpl, EcPairingGroupImpl}; 14 | use theta_proto::scheme_types::Group; 15 | use theta_proto::scheme_types::ThresholdScheme; 16 | 17 | #[repr(C)] 18 | union ECPoint { 19 | ecp: ManuallyDrop, 20 | ecp2: ManuallyDrop, 21 | fp12: ManuallyDrop, 22 | } 23 | 24 | impl std::fmt::Debug for ECPoint { 25 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 26 | write!(f, "") 27 | } 28 | } 29 | 30 | #[derive(Debug, EcPairingGroupImpl)] 31 | pub struct Bls12381 { 32 | i: u8, /* i indicates whether element is ECP, ECP2 or FP12 */ 33 | value: ECPoint, 34 | } 35 | 36 | #[derive(Debug, BigIntegerImpl)] 37 | pub struct Bls12381BIG { 38 | value: BIG, 39 | } 40 | -------------------------------------------------------------------------------- /src/core/schemes/src/integers/bigint_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interface::Serializable, 3 | rand::{RngAlgorithm, RNG}, 4 | util::printbinary, 5 | }; 6 | 7 | use super::bigint::BigInt; 8 | 9 | #[test] 10 | fn test_serialization() { 11 | let x = BigInt::new_rand(&mut RNG::new(RngAlgorithm::OsRng), 256); 12 | let mut x_bytes = x.to_bytes(); 13 | let decoded = BigInt::from_bytes(&mut x_bytes); 14 | 15 | printbinary(&x_bytes, Some("x_bytes: ")); 16 | assert!(x.equals(&decoded)); 17 | } 18 | 19 | #[test] 20 | fn test_sub() { 21 | let x = BigInt::new_int(128); 22 | let y = BigInt::new_int(48); 23 | let res = x.sub(&y); 24 | 25 | assert!(res.equals(&BigInt::new_int(80))); 26 | 27 | let y = BigInt::new_int(128); 28 | let res = x.sub(&y); 29 | 30 | assert!(res.equals(&BigInt::new_int(0))); 31 | } 32 | 33 | #[test] 34 | fn test_equals() { 35 | let x = BigInt::new_int(128); 36 | let y = BigInt::new_int(128); 37 | 38 | assert!(x.equals(&y)); 39 | } 40 | 41 | #[test] 42 | fn test_rand() { 43 | let x = BigInt::new_rand(&mut RNG::new(RngAlgorithm::OsRng), 32); 44 | println!("{}", x.to_string()); 45 | } 46 | -------------------------------------------------------------------------------- /src/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if the number of lines is provided as a parameter 4 | if [ $# -ne 1 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | num_lines=$1 10 | 11 | threshold=$(echo "(($num_lines - 1) * 1/3) + 1 " | bc) 12 | 13 | # Purge previous config 14 | rm -r conf/* 15 | 16 | # Create the server_ips.txt file 17 | ip_address="127.0.0.1" 18 | 19 | for ((i=1; i<=$num_lines; i++)) 20 | do 21 | echo "$ip_address" 22 | done > conf/server_ips.txt 23 | 24 | 25 | # Generate the configuration files 26 | cargo run --bin confgen -- --ip-file conf/server_ips.txt --port-strategy consecutive --outdir=conf 27 | 28 | # Generate the keystore files 29 | cargo run --bin thetacli -- keygen -k=${threshold} -n=${num_lines} --subjects all --output ./conf --new 30 | 31 | 32 | # Create the start_network.sh file 33 | cat > start_network.sh <> start_network.sh 41 | done 42 | 43 | echo "wait" >> start_network.sh 44 | 45 | echo "pids=\$(jobs -p)" >> start_network.sh 46 | 47 | echo "kill \$pids" >> start_network.sh 48 | 49 | chmod +x start_network.sh -------------------------------------------------------------------------------- /src/core/protocols/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_protocols" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | theta_events = {path = "../../events", version = "0.1.0"} 8 | theta_schemes = {path = "../schemes", version = "0.1.0"} 9 | theta_proto = {path = "../../proto", version = "0.1.0"} 10 | theta_network = {path="../../network"} 11 | 12 | chrono = { version = "0.4.31", features = ["serde"] } 13 | tonic = "0.8" 14 | prost = "0.11" 15 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 16 | mcore = {path="../schemes/mcore", version="0.1.0", features=["std"]} 17 | rand = "0.8.5" 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde_json = "1.0" 20 | serde_with = "1.13" 21 | hex = "0.4.3" 22 | log = "0.4.17" 23 | env_logger = "0.9.1" 24 | futures = "0.3.21" 25 | 26 | structopt = { version = "0.3", default-features = false } 27 | reqwest = { version = "0.11.10", features = ["json"] } # reqwest with JSON parsing support 28 | serde_bytes = "0.11" 29 | base64 = "0.13.0" 30 | urlencoding = "2.1.2" 31 | text_io = "0.1.12" 32 | clap = { version = "4.0.14", features = ["derive"] } 33 | 34 | [lib] 35 | name = "theta_protocols" 36 | path = "src/lib.rs" 37 | 38 | [build-dependencies] 39 | tonic-build = "0.8" 40 | prost-build = "0.11.1" 41 | -------------------------------------------------------------------------------- /src/network/src/network_manager/network_director.rs: -------------------------------------------------------------------------------- 1 | use crate::{p2p::p2p_component::P2PComponent, proxy::proxyp2p::P2PProxy, types::config::NetworkConfig}; 2 | 3 | use super::network_manager_builder::NetworkManagerBuilder; 4 | 5 | // import here all the concrete types (like P2PComponent) 6 | pub struct NetworkDirector; 7 | 8 | impl NetworkDirector{ 9 | pub fn construct_standalone_network(builder: &mut NetworkManagerBuilder, config: NetworkConfig, my_id: u32){ 10 | // Instanciathe the p2p compponent implementation 11 | let p2p_component = P2PComponent::new( 12 | config.clone(), 13 | my_id, 14 | ); 15 | 16 | builder.set_gossip_channel(Box::new(p2p_component)); 17 | } 18 | 19 | pub fn construct_proxy_network(builder: &mut NetworkManagerBuilder, config: NetworkConfig, my_id: u32){ 20 | // Instanciathe the p2p compponent implementation 21 | let p2p_proxy = P2PProxy::new( 22 | config.clone(), 23 | my_id, 24 | ); 25 | 26 | // p2p_proxy.init().await;//to move 27 | 28 | builder.set_gossip_channel(Box::new(p2p_proxy)); 29 | } 30 | } 31 | // pub fn construct_blockchain_based_network>(builder: &NetworkManagerBuilder){ 32 | 33 | // } -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/commitments/pedersen.rs: -------------------------------------------------------------------------------- 1 | use crate::groups::group::GroupElement; 2 | use crate::integers::sizedint::SizedBigInt; 3 | use crate::scheme_types_impl::GroupDetails; 4 | 5 | use crate::groups::group::GroupOperations; 6 | pub struct PedersenCommitmentParams { 7 | pub x: SizedBigInt, 8 | pub r: SizedBigInt, 9 | } 10 | 11 | impl PedersenCommitmentParams { 12 | pub fn init(x: SizedBigInt, r: SizedBigInt) -> PedersenCommitmentParams { 13 | PedersenCommitmentParams { x: x, r: r } 14 | } 15 | } 16 | 17 | pub struct PedersenCommitment { 18 | c: GroupElement, 19 | } 20 | 21 | impl PedersenCommitment { 22 | pub fn commit(params: &PedersenCommitmentParams) -> Self { 23 | let group = params.x.get_group(); 24 | let gx = GroupElement::new_pow_big(&group, ¶ms.x); 25 | let hr = &group.get_alternate_generator().pow(¶ms.r); 26 | return PedersenCommitment { c: gx.mul(&hr) }; 27 | } 28 | 29 | pub fn verify(self, params: &PedersenCommitmentParams) -> bool { 30 | let group = params.x.get_group(); 31 | let gx = GroupElement::new_pow_big(&group, ¶ms.x); 32 | let hr = &group.get_alternate_generator().pow(¶ms.r); 33 | return self.c.eq(&gx.mul(&hr)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM rust:1.74 as builder 3 | 4 | RUN apt-get update && \ 5 | apt-get install -y libssl-dev && \ 6 | apt-get install -y protobuf-compiler && \ 7 | apt-get install -y m4 8 | 9 | ENV PROJECT_PATH=/rootLibrary 10 | 11 | COPY ./src $PROJECT_PATH/threasholdLibrary 12 | 13 | WORKDIR $PROJECT_PATH/threasholdLibrary 14 | 15 | RUN cargo build --release 16 | 17 | 18 | FROM debian:12 19 | 20 | RUN apt-get update && apt-get -y install libssl-dev && rm -rf /var/lib/apt/lists/* 21 | RUN apt-get -y install libc6 22 | 23 | #Binaries 24 | COPY --from=builder /rootLibrary/threasholdLibrary/target/release/server /target/release/ 25 | COPY --from=builder /rootLibrary/threasholdLibrary/target/release/confgen /target/release/ 26 | COPY --from=builder /rootLibrary/threasholdLibrary/target/release/client /target/release/ 27 | COPY --from=builder /rootLibrary/threasholdLibrary/target/release/thetacli /target/release/ 28 | 29 | COPY --from=builder /rootLibrary/threasholdLibrary/log4rs.yaml /target/release/ 30 | COPY --from=builder /rootLibrary/threasholdLibrary/log4rs_to_file.yaml /target/release/ 31 | 32 | WORKDIR /target/release/ 33 | 34 | #after docker run you can override CMD 35 | CMD ["./server", "--", " --config-file conf/server_0.json", " --key-file conf/keys_0.json"] 36 | 37 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | //#![no_std] 21 | 22 | #![allow(clippy::many_single_char_names)] 23 | #![allow(clippy::needless_range_loop)] 24 | #![allow(clippy::manual_memcpy)] 25 | #![allow(clippy::new_without_default)] 26 | pub mod arch; 27 | pub mod aes; 28 | pub mod gcm; 29 | pub mod hmac; 30 | pub mod hash256; 31 | pub mod hash384; 32 | pub mod hash512; 33 | pub mod rand; 34 | pub mod share; 35 | pub mod sha3; 36 | pub mod nhs; 37 | pub mod x509; 38 | pub mod ed25519; 39 | pub mod secp256k1; 40 | pub mod bn254; 41 | pub mod bls12381; 42 | pub mod rsa2048; 43 | -------------------------------------------------------------------------------- /src/core/orchestration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_orchestration" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | theta_schemes = {path = "../schemes", version = "0.1.0"} 8 | theta_protocols = {path = "../protocols", version = "0.1.0"} 9 | theta_proto = {path = "../../proto", version = "0.1.0"} 10 | theta_network = {path="../../network"} 11 | theta_events = {path="../../events"} 12 | 13 | tonic = "0.8" 14 | prost = "0.11" 15 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 16 | chrono = { version = "0.4.31", features = ["serde"] } 17 | mcore = {path="../schemes/mcore", version="0.1.0", features=["std"]} 18 | rand = "0.8.5" 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | serde_with = "1.13" 22 | hex = "0.4.3" 23 | log = "0.4.17" 24 | env_logger = "0.9.1" 25 | futures = "0.3.21" 26 | 27 | structopt = { version = "0.3", default-features = false } 28 | reqwest = { version = "0.11.10", features = ["json"] } # reqwest with JSON parsing support 29 | serde_bytes = "0.11" 30 | base64 = "0.21.5" 31 | urlencoding = "2.1.2" 32 | text_io = "0.1.12" 33 | clap = { version = "4.0.14", features = ["derive"] } 34 | 35 | [lib] 36 | name = "theta_orchestration" 37 | path = "src/lib.rs" 38 | 39 | [build-dependencies] 40 | tonic-build = "0.8" 41 | prost-build = "0.11.1" 42 | -------------------------------------------------------------------------------- /src/network/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_network" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | mdns = ["libp2p-mdns"] 10 | tcp-tokio = ["libp2p-tcp", "libp2p-tcp/tokio"] 11 | 12 | [dependencies] 13 | 14 | async-std = { version = "1.11.0", features = ["attributes"] } 15 | config-file = "0.2.3" 16 | futures = "0.3.21" # for our async / await blocks 17 | libp2p = { version = "0.45.0", features = ["tcp-tokio", "mdns"]} 18 | libp2p-mdns = { version = "0.37.0", optional = true } 19 | libp2p-tcp = { version = "0.33.0", optional = true } 20 | libp2p-dns = "0.34.0" 21 | trust-dns-resolver = "0.21.2" 22 | log = "0.4.17" 23 | once_cell = "1.5" 24 | protobuf = "3.0.3" 25 | rand = "0.8.5" 26 | reqwest = { version = "0.11.10", features = ["json"] } # reqwest with JSON parsing support 27 | serde = {version = "=1.0", features = ["derive"] } 28 | serde_json = "1.0" 29 | tokio = { version = "1.15", features = ["full"] } 30 | toml = { version = "0.5.9" } 31 | time = {version = "0.3.9"} 32 | tendermint-rpc = { version = "0.23.7", features = ["http-client"] } 33 | 34 | tonic = "0.8" 35 | 36 | thetacrypt_blockchain_stub = {path="../thetacrypt_blockchain_stub", version="0.1.0"} 37 | theta_proto = {path = "../proto", version = "0.1.0"} 38 | utils = {path = "../utils", version = "0.1.0"} 39 | -------------------------------------------------------------------------------- /src/core/schemes/src/keys/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Debug, Display}; 2 | 3 | pub mod key_generator; 4 | pub mod key_store; 5 | #[cfg(test)] 6 | pub mod key_store_tests; 7 | pub mod keys; 8 | 9 | #[macro_export] 10 | macro_rules! unwrap_enum_vec { 11 | ($vec:expr, $variant:path, $err:expr) => {{ 12 | let mut vec = Vec::new(); 13 | for i in 0..$vec.len() { 14 | let val = &$vec[i]; 15 | match val { 16 | $variant(x) => { 17 | vec.push((*x).clone()); 18 | } 19 | _ => Err($err)?, 20 | } 21 | } 22 | Ok(vec) 23 | }}; 24 | } 25 | 26 | pub enum KeyStoreError { 27 | DuplicateEntry(String), 28 | IdMismatch, 29 | IdNotFound(String), 30 | } 31 | 32 | impl Display for KeyStoreError { 33 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 | match self { 35 | Self::DuplicateEntry(id) => write!(f, "Key with id '{}' already exists", id), 36 | Self::IdNotFound(id) => { 37 | write!(f, "Could not find a key with the given key_id '{}'", id) 38 | } 39 | KeyStoreError::IdMismatch => write!(f, "Key id does not match key"), 40 | } 41 | } 42 | } 43 | 44 | impl Debug for KeyStoreError { 45 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 46 | Display::fmt(&self, f) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/service/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "theta_service" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | theta_schemes = {path = "../core/schemes", version = "0.1.0"} 10 | theta_protocols = {path = "../core/protocols", version = "0.1.0"} 11 | theta_orchestration = {path = "../core/orchestration", version = "0.1.0"} 12 | theta_proto = {path = "../proto", version = "0.1.0"} 13 | theta_network = {path="../network"} 14 | theta_events = {path="../events", version = "0.1.0"} 15 | 16 | chrono = { version = "0.4.31", features = ["serde"] } 17 | tonic = "0.8" 18 | prost = "0.11" 19 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 20 | mcore = {path="../core/schemes/mcore", version="0.1.0", features=["std"]} 21 | rand = "0.8.5" 22 | serde = { version = "1.0", features = ["derive"] } 23 | serde_json = "1.0" 24 | serde_with = "1.13" 25 | hex = "0.4.3" 26 | log = "0.4.17" 27 | env_logger = "0.9.1" 28 | futures = "0.3.21" 29 | 30 | structopt = { version = "0.3", default-features = false } 31 | reqwest = { version = "0.11.10", features = ["json"] } # reqwest with JSON parsing support 32 | serde_bytes = "0.11" 33 | base64 = "0.13.0" 34 | urlencoding = "2.1.2" 35 | text_io = "0.1.12" 36 | clap = { version = "4.0.14", features = ["derive"] } 37 | 38 | log4rs = "1.1.1" 39 | 40 | [build-dependencies] 41 | tonic-build = "0.8" 42 | prost-build = "0.11.1" 43 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/common_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dl_schemes::common::{eval_pol, horner, shamir_share}, 3 | rand::{RngAlgorithm, RNG}, 4 | }; 5 | 6 | use theta_proto::scheme_types::Group; 7 | 8 | use crate::{groups::ec::bls12381::Bls12381, integers::sizedint::SizedBigInt}; 9 | 10 | const GROUP: Group = Group::Bls12381; 11 | 12 | #[test] 13 | fn test_shamir_share() { 14 | let x = SizedBigInt::new_int(&GROUP, 5); 15 | 16 | let mut rng = RNG::new(RngAlgorithm::OsRng); 17 | let (c, d) = shamir_share(&x, 2, 3, &mut rng); 18 | assert!(c.len() == 3); 19 | assert!(d.len() == 3); 20 | } 21 | 22 | #[test] 23 | fn test_eval_pol() { 24 | let mut x = SizedBigInt::new_int(&GROUP, 2); 25 | let mut a = Vec::new(); 26 | a.push(SizedBigInt::new_int(&GROUP, 1)); 27 | a.push(SizedBigInt::new_int(&GROUP, 2)); 28 | a.push(SizedBigInt::new_int(&GROUP, 3)); 29 | 30 | let res = eval_pol(&mut x, &a).rmod(&SizedBigInt::new_int(&GROUP, 7)); 31 | let c = SizedBigInt::new_int(&GROUP, 4); 32 | 33 | assert!(res.equals(&c)); 34 | } 35 | 36 | #[test] 37 | fn test_horner() { 38 | let mut x = SizedBigInt::new_int(&GROUP, 2); 39 | let mut a = Vec::new(); 40 | a.push(SizedBigInt::new_int(&GROUP, 1)); 41 | a.push(SizedBigInt::new_int(&GROUP, 2)); 42 | a.push(SizedBigInt::new_int(&GROUP, 3)); 43 | 44 | let res = horner(&mut x, &a).rmod(&SizedBigInt::new_int(&GROUP, 7)); 45 | let c = SizedBigInt::new_int(&GROUP, 4); 46 | 47 | assert!(res.equals(&c)); 48 | } 49 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/commitments/pedersen_tests.rs: -------------------------------------------------------------------------------- 1 | use theta_proto::scheme_types::Group; 2 | 3 | use crate::{ 4 | dl_schemes::commitments::{ 5 | interface::{Commitment, CommitmentParams}, 6 | pedersen::PedersenCommitmentParams, 7 | }, 8 | integers::sizedint::SizedBigInt, 9 | rand::{RngAlgorithm, RNG}, 10 | scheme_types_impl::GroupDetails, 11 | }; 12 | 13 | #[test] 14 | fn test_scheme() { 15 | let group = Group::Bls12381; 16 | let mut rng = RNG::new(RngAlgorithm::OsRng); 17 | 18 | let x = SizedBigInt::new_rand(&group, &group.get_order(), &mut rng); 19 | let r = SizedBigInt::new_rand(&group, &group.get_order(), &mut rng); 20 | 21 | let params = CommitmentParams::Pedersen(PedersenCommitmentParams::init(x, r)); 22 | let c = Commitment::commit(¶ms); 23 | 24 | let result = c.verify(¶ms); 25 | 26 | assert!(result == true); 27 | } 28 | 29 | #[test] 30 | fn test_other_committed_value() { 31 | let group = Group::Bls12381; 32 | let mut rng = RNG::new(RngAlgorithm::OsRng); 33 | 34 | let x = SizedBigInt::new_rand(&group, &group.get_order(), &mut rng); 35 | let r = SizedBigInt::new_rand(&group, &group.get_order(), &mut rng); 36 | 37 | let x_bar = SizedBigInt::new_copy(&x.add(&SizedBigInt::new_int(&group, 1))); 38 | let r_bar = SizedBigInt::new_copy(&r); 39 | 40 | let params = CommitmentParams::Pedersen(PedersenCommitmentParams::init(x, r)); 41 | let other_params = CommitmentParams::Pedersen(PedersenCommitmentParams::init(x_bar, r_bar)); 42 | 43 | let c = Commitment::commit(¶ms); 44 | 45 | let result = c.verify(&other_params); 46 | 47 | assert!(result == false); 48 | } 49 | -------------------------------------------------------------------------------- /src/Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1: Base image 2 | FROM rust:1.81 AS rust 3 | WORKDIR /app 4 | 5 | # Install cargo-chef, which will help us utilize Docker's layer caching 6 | # to speed up builds. 7 | RUN cargo install cargo-chef 8 | 9 | # Install dependencies required by compilation later on 10 | RUN apt-get update && apt-get install -yqq build-essential cmake protobuf-compiler 11 | 12 | 13 | # Stage 2: cargo chef prepare 14 | FROM rust AS planner 15 | 16 | # Make cargo-chef analyze project's structure, dependencies, ... 17 | COPY . . 18 | RUN cargo chef prepare --recipe-path recipe.json 19 | 20 | 21 | # Stage 3: Compile 22 | FROM rust AS builder 23 | 24 | # Build dependencies first. This layer can be cached later on. 25 | COPY --from=planner /app/recipe.json recipe.json 26 | RUN cargo chef cook --release --recipe-path recipe.json 27 | 28 | # Build application itself 29 | COPY . . 30 | RUN cargo build --release --bin server 31 | # Don't strictly speaking need any of these, but we can compile them for cheap 32 | # as we have a compilation cache available at this point. So we might as well. 33 | RUN cargo build --release --bin client 34 | RUN cargo build --release --bin confgen 35 | RUN cargo build --release --bin thetacli 36 | 37 | 38 | # Stage 4: Run in plain Debian container 39 | FROM debian:12-slim AS runtime 40 | 41 | WORKDIR /app 42 | COPY --from=builder /app/target/release/server /usr/local/bin/ 43 | COPY --from=builder /app/target/release/client /usr/local/bin/ 44 | COPY --from=builder /app/target/release/confgen /usr/local/bin/ 45 | COPY --from=builder /app/target/release/thetacli /usr/local/bin/ 46 | COPY log4rs.yaml /app/ 47 | COPY log4rs_to_file.yaml /app/ 48 | 49 | ENTRYPOINT ["/usr/local/bin/server"] 50 | -------------------------------------------------------------------------------- /src/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "network", 4 | "service", 5 | "core/schemes", 6 | "core/protocols", 7 | "core/orchestration", 8 | "utils", 9 | "thetacrypt_blockchain_stub", 10 | "events", 11 | ] 12 | 13 | [package] 14 | name = "thetacrypt" 15 | version = "0.1.0" 16 | edition = "2021" 17 | 18 | [dependencies] 19 | utils = {path = "utils", version = "0.1.0"} 20 | theta_schemes = {path = "core/schemes", version = "0.1.0"} 21 | theta_orchestration = {path = "core/orchestration", version = "0.1.0"} 22 | theta_protocols = {path = "core/protocols", version = "0.1.0"} 23 | theta_proto = {path = "proto", version = "0.1.0"} 24 | theta_service = {path = "service", version = "0.1.0"} 25 | theta_network = {path = "network", version = "0.1.0"} 26 | terminal-menu = "2.0.6" 27 | thetacrypt_blockchain_stub = {path = "thetacrypt_blockchain_stub", version = "0.1.0"} 28 | theta_events = {path = "events", version = "0.1.0"} 29 | tonic = "0.8" 30 | tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } 31 | 32 | serde = { version = "1.0", features = ["derive", "std"] } 33 | 34 | rand = "0.8.5" 35 | hex = "0.4.3" 36 | log = "0.4.17" 37 | log4rs = "1.1.1" 38 | env_logger = "0.9.1" 39 | clap = { version = "4.0.14", features = ["derive"] } 40 | serde_json = "1.0" 41 | thiserror = "1.0.49" 42 | base64 = "0.21.5" 43 | atty = "0.2.14" 44 | sha2 = "0.10.8" 45 | futures = "0.3" 46 | 47 | [build-dependencies] 48 | tonic-build = "0.8" 49 | 50 | [[bin]] 51 | name = "client" 52 | path = "bin/client.rs" 53 | 54 | [[bin]] 55 | name = "confgen" 56 | path = "bin/confgen.rs" 57 | 58 | [[bin]] 59 | name = "thetacli" 60 | path = "bin/thetacli.rs" 61 | 62 | [[bin]] 63 | name = "server" 64 | path = "bin/server.rs" 65 | 66 | [[bin]] 67 | name = "key_example" 68 | path = "bin/key_example.rs" 69 | -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_signature/message_types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use theta_network::types::message::{Channel, NetMessage, NetMessageMetadata}; 3 | use theta_schemes::interface::SignatureShare; 4 | 5 | use crate::interface::{ProtocolError, ProtocolMessageWrapper}; 6 | 7 | 8 | #[derive(Serialize, Deserialize)] 9 | pub enum SignatureMessage{ 10 | ShareMessage(SignatureShare), 11 | Default, 12 | } 13 | 14 | impl Default for SignatureMessage { 15 | fn default() -> Self { 16 | SignatureMessage::Default 17 | } 18 | } 19 | 20 | impl ProtocolMessageWrapper for SignatureMessage{ 21 | fn unwrap(wrapped: NetMessage) -> Result, crate::interface::ProtocolError> { 22 | let bytes = wrapped.get_message_data().to_owned(); 23 | let result = serde_json::from_str::(&String::from_utf8(bytes).expect("Error serializing the JSON")); 24 | match result { 25 | Ok(message) => { 26 | return Ok(Box::new(message)) 27 | }, 28 | Err(_) => { 29 | return Err(ProtocolError::InternalError) //To change the type of error 30 | }, 31 | }; 32 | } 33 | 34 | fn wrap(&self, instance_id: &String) -> Result { 35 | let message_data = serde_json::to_string(&self).expect("Error in serializing SignatureShareMessage for Vec").into_bytes(); 36 | let metadata = NetMessageMetadata::new(Channel::Gossip); 37 | let net_message = NetMessage::new(instance_id.clone(), metadata,message_data); 38 | return Ok(net_message) 39 | } 40 | 41 | fn is_default(&self) -> bool { 42 | match self { 43 | SignatureMessage::Default => true, 44 | _ => false 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/core/schemes/src/integers/sizedint_tests.rs: -------------------------------------------------------------------------------- 1 | use theta_proto::scheme_types::Group; 2 | 3 | use crate::{groups::ec::bls12381::Bls12381, integers::sizedint::SizedBigInt}; 4 | 5 | const GROUP: Group = Group::Bls12381; 6 | 7 | #[test] 8 | fn test_add() { 9 | let a = SizedBigInt::new_int(&GROUP, 5); 10 | let b = SizedBigInt::new_int(&GROUP, 10); 11 | let c = a.add(&b); 12 | let d = SizedBigInt::new_int(&GROUP, 15); 13 | 14 | assert!(c.equals(&d)); 15 | } 16 | 17 | #[test] 18 | fn test_mul() { 19 | let a = SizedBigInt::new_int(&GROUP, 5); 20 | let b = SizedBigInt::new_int(&GROUP, 10); 21 | let c = a.mul_mod(&b, &a); 22 | let d = SizedBigInt::new_int(&GROUP, 0); 23 | 24 | assert!(c.equals(&d)); 25 | } 26 | 27 | #[test] 28 | fn test_imul() { 29 | let a = SizedBigInt::new_int(&GROUP, 5); 30 | let b = a.imul(20); 31 | let c = SizedBigInt::new_int(&GROUP, 100); 32 | 33 | assert!(b.equals(&c)); 34 | } 35 | 36 | #[test] 37 | fn test_pow_mod() { 38 | let mut a = SizedBigInt::new_int(&GROUP, 5); 39 | let b = SizedBigInt::new_int(&GROUP, 2); 40 | let c = SizedBigInt::new_int(&GROUP, 23); 41 | let d = a.pow_mod(&b, &c); 42 | let e = SizedBigInt::new_int(&GROUP, 2); 43 | 44 | assert!(d.equals(&e)); 45 | assert!(a.equals(&SizedBigInt::new_int(&GROUP, 5))); 46 | } 47 | 48 | #[test] 49 | fn test_inv_mod() { 50 | let a = SizedBigInt::new_int(&GROUP, 3); 51 | let b = SizedBigInt::new_int(&GROUP, 7); 52 | let c = a.inv_mod(&b); 53 | let d = SizedBigInt::new_int(&GROUP, 5); 54 | 55 | assert!(c.equals(&d)); 56 | } 57 | 58 | #[test] 59 | fn test_rmod() { 60 | let a = SizedBigInt::new_int(&GROUP, 15); 61 | let b = SizedBigInt::new_int(&GROUP, 10); 62 | let c = a.rmod(&b); 63 | let d = SizedBigInt::new_int(&GROUP, 5); 64 | 65 | assert!(c.equals(&d)); 66 | } 67 | -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_coin/message_types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use theta_network::types::message::{Channel, NetMessage, NetMessageMetadata}; 3 | use theta_schemes::interface::CoinShare; 4 | 5 | use crate::interface::{ProtocolError, ProtocolMessageWrapper}; 6 | 7 | 8 | 9 | #[derive(Serialize, Deserialize)] 10 | pub enum CoinMessage{ 11 | ShareMessage(CoinShare), 12 | Default, 13 | } 14 | 15 | impl Default for CoinMessage { 16 | fn default() -> Self { 17 | CoinMessage::Default 18 | } 19 | } 20 | 21 | impl ProtocolMessageWrapper for CoinMessage { 22 | fn unwrap(wrapped: NetMessage) -> Result, crate::interface::ProtocolError> { 23 | let bytes = wrapped.get_message_data().to_owned(); 24 | let result = serde_json::from_str::(&String::from_utf8(bytes).expect("Error serializing the JSON")); 25 | match result { 26 | Ok(message) => { 27 | return Ok(Box::new(message)) 28 | }, 29 | Err(_) => { 30 | return Err(ProtocolError::InternalError) //To change the type of error 31 | }, 32 | }; 33 | } 34 | 35 | fn wrap(&self, instance_id: &String,) -> Result { 36 | let message_data = serde_json::to_string(&self).expect("Error in serializing CoinMessage for Vec").into_bytes(); 37 | let metadata = NetMessageMetadata::new(Channel::Gossip); 38 | let net_message = NetMessage::new(instance_id.clone(), metadata,message_data); 39 | return Ok(net_message) 40 | } 41 | 42 | fn is_default(&self) -> bool { 43 | match self { 44 | CoinMessage::Default => true, 45 | _ => false 46 | } 47 | } 48 | } 49 | 50 | 51 | impl CoinMessage { 52 | pub fn new(share: CoinShare) -> Self{ 53 | return CoinMessage::ShareMessage(share) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/ciphers/benchmark_tests.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use rand::Rng; 4 | 5 | use crate::{keys::KeyGenerator, rand::{RNG, RngAlgorithm}, interface::{ThresholdScheme, ThresholdCipherParams, ThresholdCipher, Ciphertext, Serializable}, group::Group}; 6 | 7 | #[test] 8 | fn serialization() { 9 | let mut keygen_rng = RNG::new(RngAlgorithm::OsRng); 10 | let private_keys = KeyGenerator::generate_keys( 11 | 7, 12 | 22, 13 | &mut keygen_rng, 14 | &ThresholdScheme::Sg02, 15 | &Group::Bls12381, 16 | &Option::None, 17 | ) 18 | .unwrap(); 19 | let private_key = &private_keys[0]; 20 | let public_key = private_key.get_public_key(); 21 | 22 | let msg_sizes = vec![1, 16, 256, 4096, 65536, 1048576, 16777216]; 23 | let mut rng = rand::thread_rng(); 24 | 25 | let label = vec![0, 1, 2, 3]; 26 | 27 | println!("step,message_size,time_microseconds"); 28 | 29 | for size in msg_sizes { 30 | let msg: Vec = (0..size).map(|_| rng.gen()).collect(); 31 | let ctxt = 32 | ThresholdCipher::encrypt(&msg, &label, &public_key, &mut ThresholdCipherParams::new()) 33 | .unwrap(); 34 | 35 | let mut ser_delta = 0; 36 | let mut der_delta = 0; 37 | for i in 0..10 { 38 | let now = Instant::now(); 39 | let bytes = ctxt.serialize().unwrap(); 40 | ser_delta += (Instant::now() - now).as_micros(); 41 | 42 | let now = Instant::now(); 43 | let _ = Ciphertext::deserialize(&bytes).unwrap(); 44 | der_delta += (Instant::now() - now).as_micros(); 45 | } 46 | ser_delta /= 10; 47 | der_delta /= 10; 48 | 49 | println!("ctxt_serialization,{},{}", size, ser_delta); 50 | println!("ctxt_deserialization,{},{}", size, der_delta); 51 | } 52 | 53 | assert!(1==2); 54 | } -------------------------------------------------------------------------------- /src/service/readme.md: -------------------------------------------------------------------------------- 1 | # The service layer 2 | 3 | The `service` package implements threshold-cryptographic protocols and an RPC server that instantiates them. 4 | All implemented protocols can be started by sending the corresponding RPC request to the provided RPC server. 5 | 6 | ## Exposing protocols over RPC 7 | 8 | The RPC types are defined in `protocol_types.proto` of the `proto` crate. Currently, the following methods are implemented: 9 | 10 | - get_public_keys_for_encryption() 11 | - decrypt() 12 | - get_decrypt_result() 13 | - sign() 14 | - get_signature_result() 15 | - flip_coin() 16 | - get_coin_result() 17 | 18 | See the documentation for each of them in `../proto/protocol_types.proto`. 19 | 20 | ## The RPC request handler 21 | 22 | The RPC request handler (defined in the `protocol_types.proto` of the `proto` crate) is implemented in `src\rpc_request_handler.rs` by the `RpcRequestHandler` struct. The logic is the following: 23 | 24 | - The request handler is constantly listening for requests. The corresponding handler method (e.g., `decrypt()`, `get_decrypt_result()`, etc.) is run every time a request is received. 25 | - For every received request (e.g., `DecryptRequest` for the `decrypt()` endpoint) make all the required correctness checks and then start a new protocol (for example a `ThresholdCipherProtocol`) instance in a new tokio thread. 26 | - Each instance is assigned and identified by a unique `instance_id`. For example, a threshold-decryption instance is identified by the concatenation of the `label` field (which is part of `DecryptRequest.ciphertext`) and the hash of the ciphertext. 27 | 28 | ### Assigning instance-id 29 | 30 | Each protocol instance must be assigned an 'instance_id'. 31 | This identifies the instance and will be used to forward messages (e.g., decryption shares for a threshold-decryption instance) to the corresponding instance. 32 | The logic for assigning instance ids is abstracted in functions such as `assign_decryption_instance_id()`. 33 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/src/cli/types.rs: -------------------------------------------------------------------------------- 1 | use std::net::IpAddr; 2 | use std::path::PathBuf; 3 | use std::str::FromStr; 4 | use std::fs; 5 | 6 | use serde::{Deserialize, Serialize}; 7 | 8 | /// PublicInfo to reach the server and its RPC endpoint. 9 | #[derive(Serialize, Deserialize, Debug, Clone)] 10 | pub struct PeerP2PInfo { 11 | pub id: u32, 12 | pub ip: String, 13 | pub p2p_port: u16, 14 | } 15 | 16 | /// Configuration of the server binary. 17 | #[derive(Serialize, Deserialize, Debug, Clone)] 18 | pub struct P2PConfig { 19 | pub peers: Vec, 20 | } 21 | 22 | impl P2PConfig { 23 | /// Read a server's configuration from a JSON encoding on disk. 24 | pub fn from_file(file: &PathBuf) -> Result { 25 | let data = match fs::read_to_string(file) { 26 | Ok(s) => s, 27 | Err(e) => return Err(format!("Error reading config file: {}", e)), 28 | }; 29 | 30 | match P2PConfig::from_json(&data) { 31 | Ok(cfg) => return Ok(cfg), 32 | Err(e) => return Err(format!("Error parsing config file: {}", e)), 33 | } 34 | } 35 | 36 | /// Build a server's configuration based on a JSON serialization. 37 | pub fn from_json(data: &str) -> Result { 38 | let cfg: P2PConfig = match serde_json::from_str(data) { 39 | Ok(cfg) => cfg, 40 | Err(e) => return Err(format!("Invalid JSON: {}", e)), 41 | }; 42 | 43 | P2PConfig::new(cfg.peers) 44 | } 45 | 46 | /// Initialize a new config struct. Performs a sanity check of passed values. 47 | pub fn new(peers: Vec) -> Result { 48 | for peer in &peers { 49 | match IpAddr::from_str(&peer.ip) { 50 | Ok(_) => {} 51 | Err(e) => return Err(format!("Invalid IP for peer {}: {}", peer.id, e)), 52 | } 53 | } 54 | 55 | Ok(P2PConfig { peers }) 56 | } 57 | } -------------------------------------------------------------------------------- /src/network/src/network_manager/network_manager_builder.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::mpsc::{Receiver, Sender}; 2 | use crate::{interface::{Gossip, TOB}, types::{config::NetworkConfig, message::NetMessage}}; 3 | 4 | use super::network_manager::NetworkManager; 5 | 6 | #[derive(Default)] 7 | pub struct NetworkManagerBuilder{ 8 | outgoing_msg_receiver: Option>, 9 | incoming_msg_sender: Option>, 10 | config: Option, //TODO: to review this Config, also the position 11 | my_id: u32, 12 | gossip_channel: Option>>, 13 | tob_channel: Option>>, 14 | } 15 | 16 | impl NetworkManagerBuilder{ 17 | 18 | pub fn set_outgoing_msg_receiver(&mut self, receiver: Receiver) { 19 | self.outgoing_msg_receiver = Some(receiver) 20 | } 21 | 22 | pub fn set_incoming_message_sender(&mut self, sender: Sender){ 23 | self.incoming_msg_sender = Some(sender) 24 | } 25 | 26 | pub fn set_config(&mut self, config: NetworkConfig){ 27 | self.config = Some(config) 28 | } 29 | 30 | pub fn set_id(&mut self, id: u32){ 31 | self.my_id = id 32 | } 33 | 34 | pub fn set_gossip_channel(&mut self, gossip_channel: Box>){ 35 | self.gossip_channel = Some(gossip_channel) 36 | } 37 | 38 | pub fn set_tob_channel(&mut self, tob_channel: Box>){ 39 | self.tob_channel = Some(tob_channel) 40 | } 41 | 42 | pub fn build(self) -> NetworkManager{ 43 | return NetworkManager::new( 44 | self.outgoing_msg_receiver.expect("Set Receiver for NetworkManager"), 45 | self.incoming_msg_sender.expect("Set Sender for NetworkManager"), 46 | self.config.expect("Set config for NetworkManager"), 47 | self.my_id, 48 | self.gossip_channel.expect("Set gossip channel for NetworkManager"), 49 | self.tob_channel 50 | ) 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/core/protocols/src/interface.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use theta_network::types::message::NetMessage; 5 | use theta_schemes::interface::SchemeError; 6 | 7 | //Here one should import the message types defined for the protoccol 8 | use crate::threshold_cipher::message_types::DecryptionMessage; 9 | 10 | #[derive(Clone, Debug)] 11 | pub enum ProtocolError { 12 | SchemeError(SchemeError), 13 | InvalidCiphertext, 14 | InstanceNotFound, 15 | InternalError, 16 | NotFinished, 17 | InvalidRound, 18 | InvalidShare, 19 | } 20 | impl From for ProtocolError { 21 | fn from(tc_error: SchemeError) -> Self { 22 | ProtocolError::SchemeError(tc_error) 23 | } 24 | } 25 | 26 | // //Probably we don't need this 27 | // #[derive(Serialize, Deserialize)] 28 | // pub enum ProtocolMessage{ 29 | // Decryption(DecryptionMessage) 30 | // } 31 | 32 | //ROSE: 33 | //try to figure out the best modular why to handle messages 34 | pub trait ProtocolMessageWrapper: Send { //Here there was a + Debug. Not sure if needed 35 | fn unwrap(wrapped: T) -> Result, ProtocolError>; //we need to Box self because we don't know yet the type 36 | fn wrap(&self, instance_id: &String) -> Result; //T here would be NetMessage 37 | fn is_default(&self) -> bool; 38 | } 39 | 40 | //ROSE: to move to the protocol 41 | // Do we need an init() ? Probably yes (with Lukas we discovered that with the two roles of cordinators and signers 42 | // it will be useful to have an init function that thakes care of additional details) 43 | pub trait ThresholdRoundProtocol { 44 | //add s function to handle checks needed to correctly start the protocol, needed or can be put in do round? 45 | type ProtocolMessage: ProtocolMessageWrapper + Default; 46 | 47 | fn do_round(&mut self) -> Result; 48 | fn is_ready_for_next_round(&self) -> bool; 49 | fn is_ready_to_finalize(&self) -> bool; 50 | fn finalize(&mut self) -> Result, ProtocolError>; 51 | fn update(&mut self, message: Self::ProtocolMessage) -> Result<(), ProtocolError>; 52 | } 53 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/ed25519/rom.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | use crate::arch::Chunk; 21 | use crate::ed25519::big::NLEN; 22 | 23 | // Base Bits= 56 24 | // Curve25519 Modulus 25 | pub const MODULUS: [Chunk; NLEN] = [ 26 | 0xFFFFFFFFFFFFED, 27 | 0xFFFFFFFFFFFFFF, 28 | 0xFFFFFFFFFFFFFF, 29 | 0xFFFFFFFFFFFFFF, 30 | 0x7FFFFFFF, 31 | ]; 32 | pub const ROI:[Chunk;NLEN]=[0xEE1B274A0EA0B0,0x1806AD2FE478C4,0x993DFBD7A72F43,0x4FC1DF0B2B4D00,0x2B832480]; 33 | pub const R2MODP: [Chunk; NLEN] = [0xA4000000000000, 0x5, 0x0, 0x0, 0x0]; 34 | pub const MCONST: Chunk = 0x13; 35 | 36 | // Ed25519 Curve 37 | pub const CURVE_COF_I: isize = 8; 38 | pub const CURVE_B_I: isize = 0; 39 | pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0]; 40 | pub const CURVE_B: [Chunk; NLEN] = [ 41 | 0xEB4DCA135978A3, 42 | 0xA4D4141D8AB75, 43 | 0x797779E8980070, 44 | 0x2B6FFE738CC740, 45 | 0x52036CEE, 46 | ]; 47 | pub const CURVE_ORDER: [Chunk; NLEN] = 48 | [0x12631A5CF5D3ED, 0xF9DEA2F79CD658, 0x14DE, 0x0, 0x10000000]; 49 | pub const CURVE_GX: [Chunk; NLEN] = [ 50 | 0x562D608F25D51A, 51 | 0xC7609525A7B2C9, 52 | 0x31FDD6DC5C692C, 53 | 0xCD6E53FEC0A4E2, 54 | 0x216936D3, 55 | ]; 56 | pub const CURVE_GY: [Chunk; NLEN] = [ 57 | 0x66666666666658, 58 | 0x66666666666666, 59 | 0x66666666666666, 60 | 0x66666666666666, 61 | 0x66666666, 62 | ]; 63 | pub const CURVE_HTPC:[Chunk;NLEN]=[0x770D93A507504F,0x8C035697F23C62,0x4C9EFDEBD397A1,0x27E0EF8595A680,0x55C19240]; 64 | -------------------------------------------------------------------------------- /demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | thetacrypt1: 5 | container_name: thetacrypt1 6 | build: 7 | context: .. 8 | network: host 9 | dockerfile: Dockerfile 10 | command: ./server --config-file conf/server_1.json --key-file conf/node1.keystore 11 | volumes: 12 | - ./tmp:/target/release/conf:Z 13 | image: rust-threshold-library 14 | ports: 15 | - "27001:27000" 16 | - "51000:51000" 17 | restart: always 18 | networks: 19 | localnet: 20 | ipv4_address: 192.167.20.2 21 | 22 | thetacrypt2: 23 | container_name: thetacrypt2 24 | build: 25 | context: .. 26 | network: host 27 | dockerfile: Dockerfile 28 | volumes: 29 | - ./tmp:/target/release/conf:Z 30 | command: ./server --config-file conf/server_2.json --key-file conf/node2.keystore 31 | image: rust-threshold-library 32 | ports: 33 | - "27002:27000" 34 | - "51001:51000" 35 | restart: always 36 | networks: 37 | localnet: 38 | ipv4_address: 192.167.20.3 39 | 40 | thetacrypt3: 41 | container_name: thetacrypt3 42 | build: 43 | context: .. 44 | network: host 45 | dockerfile: Dockerfile 46 | volumes: 47 | - ./tmp:/target/release/conf:Z 48 | command: ./server --config-file conf/server_3.json --key-file conf/node3.keystore 49 | image: rust-threshold-library 50 | ports: 51 | - "27003:27000" 52 | - "51002:51000" 53 | restart: always 54 | networks: 55 | localnet: 56 | ipv4_address: 192.167.20.4 57 | 58 | thetacrypt4: 59 | container_name: thetacrypt4 60 | build: 61 | context: .. 62 | network: host 63 | dockerfile: Dockerfile 64 | volumes: 65 | - ./tmp:/target/release/conf:Z 66 | command: ./server --config-file conf/server_4.json --key-file conf/node4.keystore 67 | image: rust-threshold-library 68 | ports: 69 | - "27004:27000" 70 | - "51003:51000" 71 | restart: always 72 | networks: 73 | localnet: 74 | ipv4_address: 192.167.20.5 75 | 76 | networks: 77 | localnet: 78 | driver: bridge 79 | name: threshold-net 80 | ipam: 81 | driver: default 82 | config: 83 | - 84 | subnet: 192.167.20.0/16 85 | -------------------------------------------------------------------------------- /src/proto/src/protocol_types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package protocol_types; 3 | 4 | import "scheme_types.proto"; // Must be relative to the "includes" in build.rs 5 | 6 | // Convention: Use proto type 'bytes' (vec in Rust) for serialized data structures 7 | // and string (String in Rust) for the rest 8 | 9 | service ThresholdCryptoLibrary { 10 | // returns one or more public keys matching the request 11 | rpc get_public_keys (KeyRequest) returns (KeyResponse); 12 | 13 | // starts a decryption protocol and returns the instance id 14 | rpc decrypt (DecryptRequest) returns (DecryptResponse); 15 | 16 | // starts a signature protocol and returns the instance id 17 | rpc sign(SignRequest) returns (SignResponse); 18 | 19 | // starts a coin flip protocol and returns the instance id 20 | rpc flip_coin (CoinRequest) returns (CoinResponse); 21 | 22 | // returns the status (and if finished, the result) of a protocol instance 23 | rpc get_status (StatusRequest) returns (StatusResponse); 24 | } 25 | 26 | // ---------- Keys ---------- 27 | message KeyRequest { 28 | } 29 | 30 | message KeyResponse { 31 | repeated scheme_types.PublicKeyEntry keys = 1; 32 | } 33 | 34 | 35 | // ---------- Ciphers ---------- 36 | message DecryptRequest { 37 | bytes ciphertext = 1; 38 | optional string key_id = 2; 39 | } 40 | 41 | message DecryptResponse { 42 | string instance_id = 1; 43 | } 44 | 45 | //------------ Signatures --------------- 46 | message SignRequest { 47 | bytes message = 1; 48 | bytes label = 2; 49 | optional string key_id = 3; 50 | scheme_types.ThresholdScheme scheme = 4; 51 | scheme_types.Group group = 5; 52 | } 53 | 54 | message SignResponse { 55 | string instance_id = 1; 56 | } 57 | 58 | //------------ Coins --------------- 59 | message CoinRequest { 60 | bytes name = 1; 61 | optional string key_id = 2; 62 | scheme_types.ThresholdScheme scheme = 3; 63 | scheme_types.Group group = 4; 64 | } 65 | 66 | message CoinResponse { 67 | string instance_id = 1; 68 | } 69 | 70 | //------------ Status -------------- 71 | message StatusRequest { 72 | string instance_id = 1; 73 | } 74 | 75 | message StatusResponse { 76 | string instance_id = 1; 77 | scheme_types.ThresholdScheme scheme = 2; 78 | scheme_types.Group group = 3; 79 | bool is_finished = 4; 80 | optional bytes result = 5; 81 | optional string key_id = 6; // TODO: remove optional as soon as key_ids are implemented 82 | } -------------------------------------------------------------------------------- /src/bin/key_example.rs: -------------------------------------------------------------------------------- 1 | use std::process::exit; 2 | 3 | use clap::Parser; 4 | use env_logger::init; 5 | use log::{error, info}; 6 | use theta_schemes::keys::key_store::KeyStore; 7 | 8 | use theta_proto::protocol_types::threshold_crypto_library_client::ThresholdCryptoLibraryClient; 9 | use theta_proto::protocol_types::KeyRequest; 10 | use utils::client::cli::ClientCli; 11 | use utils::client::types::ClientConfig; 12 | 13 | /* 14 | Short example program that retrieves all available public keys from the network 15 | and imports them to a local keystore. 16 | */ 17 | 18 | #[tokio::main] 19 | async fn main() -> Result<(), Box> { 20 | init(); 21 | 22 | let version = env!("CARGO_PKG_VERSION"); 23 | info!("Starting server, version: {}", version); 24 | 25 | let client_cli = ClientCli::parse(); 26 | let mut keystore = KeyStore::new(); 27 | 28 | info!( 29 | "Loading configuration from file: {}", 30 | client_cli 31 | .config_file 32 | .to_str() 33 | .unwrap_or("Unable to print path, was not valid UTF-8"), 34 | ); 35 | let config = match ClientConfig::from_file(&client_cli.config_file) { 36 | Ok(cfg) => cfg, 37 | Err(e) => { 38 | error!("{}", e); 39 | exit(1); 40 | } 41 | }; 42 | 43 | let mut connections = connect_to_all_local(config).await; 44 | let response = connections[0].get_public_keys(KeyRequest {}).await; 45 | if response.is_ok() { 46 | let response = response.unwrap(); 47 | let keys = &response.get_ref().keys; 48 | if keystore.import_public_keys(keys).is_ok() { 49 | println!(">> Successfully imported public keys from server."); 50 | println!("{}", keystore.to_string()); 51 | } 52 | } else { 53 | println!("Error fetching public keys!"); 54 | } 55 | 56 | Ok(()) 57 | } 58 | 59 | async fn connect_to_all_local( 60 | config: ClientConfig, 61 | ) -> Vec> { 62 | let mut connections = Vec::new(); 63 | for peer in config.peers.iter() { 64 | let ip = peer.ip.clone(); 65 | let port = peer.rpc_port; 66 | let addr = format!("http://[{ip}]:{port}"); 67 | connections.push( 68 | ThresholdCryptoLibraryClient::connect(addr.clone()) 69 | .await 70 | .unwrap(), 71 | ); 72 | } 73 | println!(">> Established connection to network."); 74 | connections 75 | } 76 | -------------------------------------------------------------------------------- /src/utils/src/client/types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::fs; 3 | 4 | use std::net::IpAddr; 5 | use std::path::PathBuf; 6 | use std::str::FromStr; 7 | 8 | /// PublicInfo to reach the server and its RPC endpoint. 9 | #[derive(Serialize, Deserialize, Debug, Clone)] 10 | pub struct PeerPublicInfo { 11 | pub id: u32, 12 | pub ip: String, 13 | pub rpc_port: u16, 14 | } 15 | 16 | /// Configuration of the server binary. 17 | #[derive(Serialize, Deserialize, Debug, Clone)] 18 | pub struct ClientConfig { 19 | pub peers: Vec, 20 | } 21 | 22 | impl ClientConfig { 23 | /// Read a server's configuration from a JSON encoding on disk. 24 | pub fn from_file(file: &PathBuf) -> Result { 25 | let data = match fs::read_to_string(file) { 26 | Ok(s) => s, 27 | Err(e) => return Err(format!("Error reading config file: {}", e)), 28 | }; 29 | 30 | match ClientConfig::from_json(&data) { 31 | Ok(cfg) => return Ok(cfg), 32 | Err(e) => return Err(format!("Error parsing config file: {}", e)), 33 | } 34 | } 35 | 36 | /// Build a server's configuration based on a JSON serialization. 37 | pub fn from_json(data: &str) -> Result { 38 | let cfg: ClientConfig = match serde_json::from_str(data) { 39 | Ok(cfg) => cfg, 40 | Err(e) => return Err(format!("Invalid JSON: {}", e)), 41 | }; 42 | 43 | ClientConfig::new(cfg.peers) 44 | } 45 | 46 | /// Initialize a new config struct. Performs a sanity check of passed values. 47 | pub fn new(peers: Vec) -> Result { 48 | for peer in &peers { 49 | match IpAddr::from_str(&peer.ip) { 50 | Ok(_) => {} 51 | Err(e) => return Err(format!("Invalid IP for peer {}: {}", peer.id, e)), 52 | } 53 | } 54 | 55 | Ok(ClientConfig { peers }) 56 | } 57 | 58 | /// Get list of all peers' IDs, sorted by the order in which they appear in the config file. 59 | pub fn peer_ids(&self) -> Vec { 60 | self.peers.iter().map(|p| p.id).collect() 61 | } 62 | 63 | /// Get list of all peers' IPs, sorted by the order in which they appear in the config file. 64 | pub fn peer_ips(&self) -> Vec { 65 | self.peers.iter().map(|p| p.ip.clone()).collect() 66 | } 67 | 68 | /// Get list of all peers' RPC ports, sorted by the order in which they appear in the config 69 | /// file. 70 | pub fn peer_rpc_ports(&self) -> Vec { 71 | self.peers.iter().map(|p| p.rpc_port).collect() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/core/schemes/src/bin/group_generator.rs: -------------------------------------------------------------------------------- 1 | use mcore::hash256::HASH256; 2 | use theta_proto::scheme_types::Group; 3 | use theta_schemes::groups::group::GroupOperations; 4 | use theta_schemes::{groups::group::GroupElement, scheme_types_impl::GroupDetails}; 5 | // This binary can be used to generate a second generator for the given cyclic EC-based groups. 6 | // The generator is chosen by mapping the SHA256 hash of the string 7 | // "thetacrypt_"" to a point on the respective elliptic curve. 8 | // That point is then chosen as generator. 9 | fn main() { 10 | let groups: Vec = vec![Group::Bls12381, Group::Bn254]; 11 | 12 | // Linux version 6.4 commit hash 13 | // https://github.com/torvalds/linux/commit/6995e2de6891c724bfeb2db33d7b87775f913ad1 14 | let seed: &str = "thetacrypt_6995e2de6891c724bfeb2db33d7b87775f913ad1"; 15 | 16 | let bytes = seed.as_bytes(); 17 | 18 | let mut hasher = HASH256::new(); 19 | hasher.process_array(bytes); 20 | 21 | // Hash will be 14fad7f1b49b586b13149dd8b07cb67f89c416e3bd216e12e110ae66680c44a1 22 | let hash = hasher.hash(); 23 | 24 | for group in groups { 25 | let computed_generator = GroupElement::new_hash(&group, &hash); 26 | let predefined_generator = group.get_alternate_generator(); 27 | println!( 28 | "computed generator for group {}: {}", 29 | group.as_str_name(), 30 | computed_generator.to_string() 31 | ); 32 | println!( 33 | "predefined generator for group {}: {}", 34 | group.as_str_name(), 35 | predefined_generator.to_string() 36 | ); 37 | 38 | // Output: 39 | // computed generator for group Bls12381: (15923CA30404617E50806EC015F2597157B75D0BD342EF2A5FC1CB4041E89AC356806FD04CCC0B118C803F0006CD9413,1511F2A6BBF3F63561A41D3A49CCFF50DF35B9AD116AC539D1AEBDFC3873AEB5F6EAACADB00C4B36EFD000904BC12833) 40 | // predefined generator for group Bls12381: (15923CA30404617E50806EC015F2597157B75D0BD342EF2A5FC1CB4041E89AC356806FD04CCC0B118C803F0006CD9413,1511F2A6BBF3F63561A41D3A49CCFF50DF35B9AD116AC539D1AEBDFC3873AEB5F6EAACADB00C4B36EFD000904BC12833) 41 | // computed generator for group Bn254: (0568E3BA9ADD8FB3842403FF1E7D04AEADBE38992C2CDB3AE8F520398DFBF603,1215AAA15E82FAFC3522034DE4F3FE3C18075AFE109A413BAAFC47577F76D640) 42 | // predefined generator for group Bn254: (0568E3BA9ADD8FB3842403FF1E7D04AEADBE38992C2CDB3AE8F520398DFBF603,1215AAA15E82FAFC3522034DE4F3FE3C18075AFE109A413BAAFC47577F76D640) 43 | 44 | // Assert that the predefined alternative generator (defined in code) and the computed one match 45 | // This means that the generators defined in code have been generated using the method in this program. 46 | assert_eq!(computed_generator, predefined_generator); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/core/orchestration/src/instance_manager/instance.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use clap::error; 3 | use theta_proto::scheme_types::{Group, ThresholdScheme}; 4 | use theta_protocols::interface::ProtocolError; 5 | use tokio::sync::mpsc::error::SendError; 6 | use theta_network::types::message::NetMessage; 7 | use log::error; 8 | 9 | pub struct Instance { 10 | id: String, 11 | scheme: ThresholdScheme, 12 | group: Group, 13 | message_channel_sender: Option>, 14 | status: String, 15 | finished: bool, 16 | result: Option, ProtocolError>>, 17 | } 18 | 19 | impl fmt::Display for Instance { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | write!( 22 | f, 23 | "Instance {{\nid:{}\n, scheme:{}\ngroup:{}\nstatus:{}\n }}", 24 | self.id, 25 | self.scheme.as_str_name(), 26 | self.group.as_str_name(), 27 | &self.status 28 | ) 29 | } 30 | } 31 | 32 | impl Instance { 33 | pub fn new( 34 | id: String, 35 | scheme: ThresholdScheme, 36 | group: Group, 37 | message_channel_sender: Option>, 38 | ) -> Self { 39 | return Self { 40 | id, 41 | scheme, 42 | group, 43 | message_channel_sender, 44 | status: String::from("created"), 45 | finished: false, 46 | result: Option::None, 47 | }; 48 | } 49 | 50 | pub fn set_status(&mut self, status: &str) { 51 | self.status = String::from(status); 52 | } 53 | 54 | pub fn is_finished(&self) -> bool { 55 | return self.finished; 56 | } 57 | 58 | pub fn get_result(&self) -> &Option, ProtocolError>> { 59 | return &self.result; 60 | } 61 | 62 | pub fn set_result(&mut self, result: Result, ProtocolError>) { 63 | self.result = Some(result); 64 | self.finished = true; 65 | if let Some(sender) = self.message_channel_sender.take(){ 66 | drop(sender); 67 | } 68 | } 69 | 70 | pub fn get_scheme(&self) -> ThresholdScheme { 71 | self.scheme.clone() 72 | } 73 | 74 | pub fn get_group(&self) -> Group { 75 | self.group.clone() 76 | } 77 | 78 | pub async fn send_message(&self, message: NetMessage) -> Result<(), SendError> { 79 | if let Some(sender) = &self.message_channel_sender { 80 | return sender.send(message).await 81 | } 82 | error!("Trying to send message to finished instance"); 83 | return Err(SendError(message)); 84 | } 85 | 86 | pub fn get_sender(&self) -> Option>{ 87 | self.message_channel_sender.clone() 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/network/src/types/config.rs: -------------------------------------------------------------------------------- 1 | use libp2p::multiaddr::Multiaddr; 2 | use serde::{Deserialize, Serialize}; 3 | use utils::server::types::{Peer, ProxyNode, ServerConfig}; 4 | 5 | #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] 6 | pub struct NetworkPeer{ 7 | pub id: u32, 8 | pub ip: String, 9 | pub port: u16, 10 | } 11 | 12 | #[derive(Serialize, Deserialize, Debug, Clone)] 13 | pub struct NetworkProxy{ 14 | pub ip: String, 15 | pub port: u16, 16 | } 17 | 18 | #[derive(Serialize, Deserialize, Debug, Clone)] 19 | pub struct NetworkConfig { 20 | pub local_peer: NetworkPeer, 21 | pub peers: Option>, 22 | pub proxy: Option, 23 | pub base_listen_address: String, 24 | } 25 | 26 | impl NetworkPeer{ 27 | pub fn new(peer: &Peer)-> Self{ 28 | return NetworkPeer{ 29 | id: peer.id, 30 | ip: peer.ip.clone(), 31 | port: peer.p2p_port 32 | } 33 | } 34 | } 35 | 36 | impl NetworkProxy{ 37 | pub fn new(peer: &ProxyNode)-> Self{ 38 | return NetworkProxy{ 39 | ip: peer.ip.clone(), 40 | port: peer.port 41 | } 42 | } 43 | } 44 | 45 | impl NetworkConfig { 46 | 47 | pub fn new(server_config: &ServerConfig)-> Result{ 48 | 49 | let mut local_peer = NetworkPeer::default(); 50 | 51 | if let Some(peer) = server_config.self_peer(){ 52 | local_peer = NetworkPeer::new(peer); 53 | } 54 | 55 | if local_peer == NetworkPeer::default() { 56 | return Err("No local information to setup the peer".to_string()) 57 | } 58 | 59 | let mut network_peers:Option> = None; 60 | 61 | let server_peers:Vec = server_config.peers 62 | .iter() 63 | .map(|peer| 64 | NetworkPeer::new(peer) 65 | ) 66 | .collect(); 67 | 68 | if server_peers.len() > 1 { 69 | network_peers = Some(server_peers); 70 | } 71 | 72 | let mut proxy_peer:Option = None; 73 | 74 | if let Some(proxy) = server_config.get_proxy_node(){ 75 | proxy_peer = Some(NetworkProxy::new(proxy)); 76 | } 77 | 78 | Ok(NetworkConfig{ 79 | local_peer, 80 | peers: network_peers, 81 | proxy: proxy_peer, 82 | base_listen_address: server_config.listen_address.clone(), 83 | }) 84 | } 85 | 86 | pub fn get_p2p_listen_addr(&self) -> Multiaddr { 87 | format!("/ip4/{}/tcp/{}", self.base_listen_address, self.local_peer.port) 88 | .parse() 89 | .expect(&format!( 90 | ">> NET: Fatal error: Could not open P2P listen port {}.", 91 | self.local_peer.port 92 | )) 93 | } 94 | } -------------------------------------------------------------------------------- /src/core/protocols/src/frost/message_types.rs: -------------------------------------------------------------------------------- 1 | use log::{error, info, warn}; 2 | use serde::{Deserialize, Serialize}; 3 | use theta_network::types::message::{Channel, NetMessage, NetMessageMetadata}; 4 | use theta_schemes::{ 5 | dl_schemes::signatures::frost::{FrostSignatureShare, PublicCommitment}, 6 | interface::{DecryptionShare, Serializable}, 7 | }; 8 | 9 | use crate::interface::{ProtocolError, ProtocolMessageWrapper}; 10 | 11 | use super::protocol::FrostPrecomputation; 12 | 13 | #[derive(Serialize, Deserialize, Clone, Debug, Default)] 14 | pub struct FrostMessage { 15 | pub(crate) id: u16, 16 | pub(crate) data: FrostData, 17 | } 18 | 19 | #[repr(C)] 20 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 21 | pub enum FrostData { 22 | Commitment(PublicCommitment), 23 | Share(FrostSignatureShare), 24 | Precomputation(Vec), 25 | Default, 26 | } 27 | 28 | impl Default for FrostData { 29 | fn default() -> Self { 30 | FrostData::Default 31 | } 32 | } 33 | 34 | //consider that in protocols like frost you might have different kind of messages that needs the conversion 35 | //for the serialization 36 | // TODO: create macro for the following implementation 37 | impl ProtocolMessageWrapper for FrostMessage { 38 | fn unwrap(wrapped: NetMessage) -> Result, ProtocolError> { 39 | let bytes = wrapped.get_message_data().to_owned(); 40 | let result = serde_json::from_str::( 41 | &String::from_utf8(bytes).expect("Error serializing the JSON"), 42 | ); 43 | match result { 44 | Ok(message) => { 45 | let mut msg = message.clone(); 46 | // msg.id = wrapped.get_metadata().get_sender().clone(); //TODO: to implement the logic in the network 47 | return Ok(Box::new(msg)); 48 | } 49 | Err(_) => { 50 | return Err(ProtocolError::InternalError); //To change the type of error 51 | } 52 | }; 53 | } 54 | 55 | ///wrap() provides the logic to correctly create a NetMessage and add the necessary metadata for the medium to use for the delivery. 56 | // TODO: at this level we are not able to distiguish between the messages (if there is more than one). 57 | // These functions (or at least wrap) needs to be implemented for each value of the enum 58 | fn wrap(&self, instance_id: &String) -> Result { 59 | let message_data = serde_json::to_string(&self) 60 | .expect("Error in serializing FrostMessage for Vec") 61 | .into_bytes(); 62 | let metadata = NetMessageMetadata::new(Channel::Gossip); 63 | let net_message = NetMessage::new(instance_id.clone(), metadata, message_data); 64 | return Ok(net_message); 65 | } 66 | 67 | fn is_default(&self) -> bool { 68 | match self.data { 69 | FrostData::Default => true, 70 | _ => false, 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/utils/src/confgen/cli.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt::Display, path::PathBuf}; 2 | 3 | use clap::{Parser, ValueEnum}; 4 | 5 | #[derive(Parser, Debug)] 6 | pub struct ConfgenCli { 7 | #[arg( 8 | long, 9 | help = "Port to use for listening for RPC requests.", 10 | default_value_t = 51000 11 | )] 12 | pub rpc_port: u16, 13 | #[arg( 14 | long, 15 | help = "Port to use for P2P networking layer.", 16 | default_value_t = 50000 17 | )] 18 | pub p2p_port: u16, 19 | #[arg( 20 | short, 21 | long, 22 | help = "Address for RPC and networking layers.", 23 | default_value_t = String::from("0.0.0.0") 24 | )] 25 | pub listen_address: String, 26 | #[arg( 27 | long, 28 | help = "Strategy to use to assign P2P and RPC ports. Static uses the same ports for all servers. Consecutive starts at the provided ports, and increments them by one per server.", 29 | default_value_t = PortStrategy::Static, 30 | )] 31 | pub port_strategy: PortStrategy, 32 | 33 | #[arg( 34 | long, 35 | help = "Path to file containing IPs of servers, one per line. Required." 36 | )] 37 | pub ip_file: PathBuf, 38 | 39 | #[arg( 40 | long, 41 | help = "Controls whether to shuffle list of peers in each configuration file. This can help ensure that servers do not all connect to the same primary peer.", 42 | default_value_t = false 43 | )] 44 | pub shuffle_peers: bool, 45 | 46 | #[arg( 47 | long, 48 | help = "Path to file into which to have server store benchmarking events. If unset, benchmarking events are discarded." 49 | )] 50 | pub event_file: Option, 51 | 52 | #[arg( 53 | short, 54 | long, 55 | help = "Directory in which to place generated config files. Required. Path up to output directory must exist." 56 | )] 57 | pub outdir: PathBuf, 58 | #[arg(short, long, help = "Integration with a target blockchain platform.")] 59 | pub integration: bool, 60 | #[arg( 61 | long, 62 | help = "Path to file containing IPs of nodes of blockchain target platform, one per line." 63 | )] 64 | pub integration_file: Option, 65 | #[arg( 66 | long, 67 | help = "Port to use for connecting to the proxy. Generally the proxy is a blockchain validator." 68 | )] 69 | pub proxy_port: Option, 70 | #[arg(short, 71 | long, 72 | help = "Flag for stub file generation")] 73 | pub stub: bool, 74 | } 75 | 76 | /// Enum representing how ports are assigned to servers. Static uses the same port for all servers, 77 | /// while consecutive uses incremental ports. 78 | #[derive(ValueEnum, Debug, Clone)] 79 | pub enum PortStrategy { 80 | Consecutive, 81 | Static, 82 | } 83 | 84 | impl Display for PortStrategy { 85 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 86 | match self { 87 | PortStrategy::Consecutive => write!(f, "consecutive"), 88 | PortStrategy::Static => write!(f, "static"), 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/core/schemes/src/rsa_schemes/keygen.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | use crate::rand::RNG; 3 | use crate::{rsa_schemes::{common::{gen_strong_prime, fac}, bigint::RsaBigInt}, BIGINT, ONE}; 4 | 5 | use super::{common::shamir_share, signatures::sh00::{Sh00PrivateKey, Sh00PublicKey, Sh00VerificationKey}}; 6 | 7 | const DEBUG:bool = false; 8 | 9 | pub enum RsaScheme { 10 | Sh00(usize) 11 | } 12 | 13 | pub enum RsaPrivateKey { 14 | Sh00(Sh00PrivateKey) 15 | } 16 | 17 | pub struct RsaKeyGenerator {} 18 | 19 | impl RsaKeyGenerator { 20 | pub fn generate_keys(k: usize, n: usize, rng: &mut RNG, scheme: RsaScheme) -> Vec { 21 | match scheme { 22 | RsaScheme::Sh00(MODSIZE) => { 23 | let PLEN = MODSIZE/2 - 2; 24 | 25 | let mut p1 = RsaBigInt::new_rand(rng, PLEN); 26 | let mut q1 = RsaBigInt::new_rand(rng, PLEN); 27 | 28 | let mut p: RsaBigInt = RsaBigInt::new(); 29 | let mut q: RsaBigInt = RsaBigInt::new(); 30 | 31 | let e = BIGINT!(65537); // Question: Should we be able to change this? 32 | 33 | if DEBUG { debug!("generating strong primes..."); } 34 | 35 | let now = Instant::now(); 36 | gen_strong_prime(&mut p1, &mut p, &e, rng, PLEN); 37 | let elapsed_time = now.elapsed().as_millis(); 38 | if DEBUG { debug!("found first prime p in {}ms: {}", elapsed_time, p.to_string()); } 39 | 40 | let now = Instant::now(); 41 | gen_strong_prime(&mut q1, &mut q, &e, rng, PLEN); 42 | let elapsed_time = now.elapsed().as_millis(); 43 | if DEBUG { debug!("found second prime q in {}ms: {}", elapsed_time, q.to_string()); } 44 | 45 | let N = p.mul(&q); 46 | let m = p1.mul(&q1); 47 | 48 | let v = RsaBigInt::new_rand(rng, MODSIZE - 1).pow(2).rmod(&N); 49 | 50 | let d = e.inv_mod(&m); 51 | 52 | let delta = fac(n); 53 | let (xi, vi) = shamir_share(&d, k, n, &N, &m, &v, MODSIZE, rng); 54 | 55 | let mut u; 56 | let mut up; 57 | let mut uq; 58 | loop { 59 | u = RsaBigInt::new_rand(rng, MODSIZE - 1); 60 | up = u.pow_mod(&p1, &p); 61 | uq = u.pow_mod(&q1, &q); 62 | if up.equals(&ONE!()) != uq.equals(&ONE!()) { 63 | break; 64 | } 65 | } 66 | 67 | let verificationKey = Sh00VerificationKey::new(v, vi, u); 68 | let pubkey = Sh00PublicKey::new(k as u32, N, e.clone(), verificationKey, delta, MODSIZE); 69 | 70 | let mut pks: Vec = Vec::new(); 71 | for i in 0..n { 72 | pks.push(RsaPrivateKey::Sh00( 73 | Sh00PrivateKey::new(xi[i].0, m.clone(), xi[i].1.clone(), pubkey.clone()))) 74 | } 75 | pks 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/utils/src/server/dirutil.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{create_dir, remove_file, File}; 2 | use std::path::PathBuf; 3 | 4 | use log::debug; 5 | 6 | /// Ensure the given directory exists, creating it if it does not. 7 | /// 8 | /// If either the checking or creation fails, an error is returned. 9 | pub fn ensure_directory_exists(dir: &PathBuf) -> Result<(), String> { 10 | debug!("Ensuring that directory exists"); 11 | 12 | let exists = match dir.try_exists() { 13 | Ok(b) => b, 14 | Err(e) => { 15 | return Err(format!( 16 | "Error checking existence of output directory: {}", 17 | e 18 | )); 19 | } 20 | }; 21 | 22 | if !exists { 23 | match create_dir(dir) { 24 | Ok(_) => debug!("Created output directory"), 25 | Err(e) => { 26 | return Err(format!("Error creating output directory: {}", e)); 27 | } 28 | } 29 | } 30 | 31 | Ok(()) 32 | } 33 | 34 | /// Ensures if the given directory is empty. 35 | /// 36 | /// Returns an error if checking fails, or it is not empty. 37 | pub fn ensure_directory_is_empty(dir: &PathBuf) -> Result<(), String> { 38 | debug!("Ensuring that output directory is empty"); 39 | 40 | let mut dir_entries = match dir.read_dir() { 41 | Ok(d) => d, 42 | Err(e) => { 43 | return Err(format!( 44 | "Error checking contents of output directory: {}", 45 | e 46 | )); 47 | } 48 | }; 49 | 50 | let is_empty = dir_entries.next().is_none(); 51 | if !is_empty { 52 | return Err(format!("Output directory is not empty")); 53 | } 54 | 55 | Ok(()) 56 | } 57 | 58 | pub fn ensure_directory_is_writeable(dir: &PathBuf) -> Result<(), String> { 59 | debug!("Ensuring that directory is writeable"); 60 | 61 | let mut test_file = dir.clone(); 62 | test_file.push("foo"); 63 | match File::create(&test_file) { 64 | Ok(_) => debug!("Successfully created file in output directory"), 65 | Err(e) => { 66 | return Err(format!("Unable to write file to output directory: {}", e)); 67 | } 68 | }; 69 | 70 | match remove_file(test_file) { 71 | Ok(_) => debug!("Successfully removed file in output directory"), 72 | Err(e) => { 73 | return Err(format!( 74 | "Unable to remove test file in output directory: {}", 75 | e 76 | )); 77 | } 78 | } 79 | 80 | Ok(()) 81 | } 82 | 83 | /// Checks if the given directory is suitable to write the keygen's output to. 84 | /// 85 | /// This ensures that: 86 | /// - The directory exists 87 | /// - The directory is empty 88 | /// - The directory is writeable 89 | /// 90 | /// Returns an error message describing why the directory is not suitable, in case of failure. 91 | pub fn ensure_sane_output_directory(dir: &PathBuf, require_empty: bool) -> Result<(), String> { 92 | debug!("Checking output directory: {}", dir.display()); 93 | 94 | ensure_directory_exists(dir)?; 95 | if require_empty { 96 | ensure_directory_is_empty(dir)?; 97 | } 98 | ensure_directory_is_writeable(dir)?; 99 | 100 | Ok(()) 101 | } 102 | -------------------------------------------------------------------------------- /demo/readme.md: -------------------------------------------------------------------------------- 1 | # Demo application 2 | 3 | ## Introduction 4 | 5 | The demo application aims at showcasing the usage of Thetacrypt in a distributed deployment. Thetacrypt has been designed with two system configurations in mind. The first one entails the use of Thetacrypt as a standalone distributed service and requires the development of an application that wants to use it. The second configuration is the integration with a blockchain platform. In this case, an instance of Thetacrypt will run on each validator node of a blockchain and the service can be called from a smart contract upon the delivery of a consensus decision. 6 | 7 | To make it simpler to run and try out our service we provide a demo application with Docker. In this way to run the demo you just need docker installed on your machine. 8 | 9 | ## Local configuration 10 | 11 | A `Makefile` provides a step-by-step guide to learning about our software. 12 | 13 | The Makefile presents the following rules: 14 | 15 | - *set-up*: it creates a temporary directory, `tmp`. `tmp` will be a shared volume between the host and the containers running a Thetacrypt image and will allow the users to read the generated initial config files needed by the nodes of the network.
16 |
The `tmp` directory at the end of this first step will contain a text file, `server_ips.txt`, containing the list of IPs of our library nodes.
17 | 18 | - *build-docker*: builds the library docker image, `rust-threshold-library`, needed for subsequent steps. 19 | 20 | - *config-files*: generates configuration files for every Thetacrypt instance. While the script `confgen` is used to provide the network information of each instance, the script `Thetacli` with the parameter `keygen` is used to generate the key shares for each of them. All the resulting files will be placed in the shared volume `tmp`, mapped to the `conf` directory under `src/protocol` in the root directory. To read more about these scripts you can refer to the library documentation. 21 | 22 | - *demo-start*: calls the `docker-compose.yml` file to build a network of four Thetacrypt nodes. 23 | 24 | - *demo-stop*: performs just a command to stop all the running containers built from the `docker-compose.yml`. 25 | 26 | - *client-start*: provides the right docker instruction to run a client script that connects to all the servers. 27 | 28 | - *clean-up*: removes the `tmp` directory. 29 | 30 | ### How to run the demo 31 | 32 | 1) Clone the directory
33 | ``` 34 | git clone 35 | cd /demo 36 | ``` 37 | 2) Run the necessary rules to prepare the environment and start the network of nodes inside docker
38 | ``` 39 | make set-up 40 | make build-docker 41 | make config-files 42 | make demo-start 43 | ``` 44 | 3) The last step will allow you to run a client app that starts the interaction with every thetacrypt node in the network. Open another terminal window and type: 45 | ``` 46 | make client-start 47 | ``` 48 | 49 | In this way, you make use of the image of the library already built and run everything inside the docker network defined in the `docker-compose.yml`. 50 | 51 | Alternatively, you can run the client script on your host: 52 | 53 | ``` 54 | cd ../src/protocols 55 | cargo run --bin client -- --config-file=../../demo/tmp/client.json 56 | ``` 57 | 58 | Be aware that in this case, you need the toolchain and all the dependencies to run a Rust program. 59 | -------------------------------------------------------------------------------- /src/core/schemes/src/rand.rs: -------------------------------------------------------------------------------- 1 | use std::time::SystemTime; 2 | 3 | use mcore::rand::{RAND_impl, RAND}; 4 | use rand::{rngs::OsRng, RngCore}; 5 | 6 | pub enum RngAlgorithm { 7 | MarsagliaZaman, // should only be used for testing 8 | Static(String), // should only be used for testing 9 | OsRng, // use this for production 10 | } 11 | 12 | pub enum RNG { 13 | MarsagliaZaman(RAND_impl), 14 | OsRng(OsRng), 15 | Static(StaticRNG), 16 | } 17 | 18 | impl RAND for RNG { 19 | fn seed(&mut self, rawlen: usize, raw: &[u8]) { 20 | match self { 21 | RNG::MarsagliaZaman(rng) => rng.seed(rawlen, raw), 22 | RNG::OsRng(_rng) => {} 23 | _ => {} 24 | } 25 | } 26 | 27 | fn getbyte(&mut self) -> u8 { 28 | match self { 29 | RNG::MarsagliaZaman(rng) => return rng.getbyte(), 30 | RNG::OsRng(rng) => { 31 | return rng.next_u32().to_be_bytes()[0]; 32 | } 33 | RNG::Static(rng) => rng.getbyte(), 34 | } 35 | } 36 | } 37 | 38 | impl RNG { 39 | pub fn new(alg: RngAlgorithm) -> RNG { 40 | let mut raw: [u8; 100] = [0; 100]; 41 | let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH); 42 | 43 | match now { 44 | Ok(_n) => { 45 | let ms = _n.as_millis(); 46 | for i in 0..15 { 47 | raw[i] = (ms << i) as u8 48 | } 49 | } 50 | Err(_) => { 51 | panic!("Error initializing random number generator") 52 | } 53 | } 54 | 55 | match alg { 56 | RngAlgorithm::MarsagliaZaman => { 57 | let mut rng = RAND_impl::new(); 58 | rng.clean(); 59 | rng.seed(16, &raw); 60 | return RNG::MarsagliaZaman(rng); 61 | } 62 | 63 | RngAlgorithm::OsRng => { 64 | let rng = OsRng::default(); 65 | return RNG::OsRng(rng); 66 | } 67 | 68 | RngAlgorithm::Static(seed) => { 69 | let rng = StaticRNG::new(seed, true); 70 | return RNG::Static(rng); 71 | } 72 | } 73 | } 74 | 75 | pub fn random_bytes(&mut self, num: usize) -> Vec { 76 | let mut result = Vec::new(); 77 | for _ in 0..num { 78 | result.push(self.getbyte()); 79 | } 80 | result 81 | } 82 | } 83 | 84 | pub struct StaticRNG { 85 | seed: Vec, 86 | index: usize, 87 | } 88 | 89 | impl StaticRNG { 90 | pub fn new(seed: String, little_endian: bool) -> Self { 91 | let t = hex::decode(seed); 92 | let mut seed = Vec::new(); 93 | if t.is_ok() { 94 | seed = t.unwrap(); 95 | 96 | if little_endian { 97 | seed.reverse(); 98 | } 99 | } 100 | 101 | let index = 0; 102 | 103 | return StaticRNG { index, seed }; 104 | } 105 | 106 | pub fn getbyte(&mut self) -> u8 { 107 | let byte = self.seed[self.index].clone(); 108 | 109 | self.index += 1; 110 | if self.index >= self.seed.len() { 111 | self.index = 0; 112 | } 113 | 114 | byte 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/core/protocols/readme.md: -------------------------------------------------------------------------------- 1 | # Protocols 2 | 3 | Threshold protocols are implemented in the `src/` directory, e.g., 4 | `src/threshold_cipher`. 5 | 6 | By now we support `threshold_chipher`, `threshold_signature`, `threshold_coin` implementations. 7 | 8 | For every type of protocol implemented, there should be a dedicated directory that internally provides the following structure: 9 | 10 | ``` 11 | - src 12 | | - threshold_cipher 13 | | | - protocols.rs 14 | | | - message_types.rs 15 | | | - mod.rs 16 | ``` 17 | 18 | Sections below detail what every file should contain. 19 | 20 | ## Functions in a protocol 21 | 22 | A protocol must expose two functions, run() and terminate(). 23 | The caller should only have to call run() to start the protocol instance. 24 | 25 | - About run(): 26 | The function run() runs for the whole lifetime of the instance and implements the protocol logic. 27 | In the beginning, it must make the necessary validity checks (e.g., the validity of ciphertext). 28 | There is a loop(), which handles incoming shares. The loop exits when the instance is finished. 29 | This function is also responsible for returning the result to the caller. 30 | 31 | - About terminate(): 32 | It is called by the instance to clean up any remaining data. 33 | 34 | ### Fields in a protocol 35 | 36 | Protocol types contain the following fields. 37 | See for example the `ThresholdCipherProtocol` in `src\threshold_cipher/protocol.rs`. 38 | 39 | - chan_in: 40 | The receiver end of a channel. Messages (e.g., decryption shares) destined for this instance will be received here. 41 | - chan_out: 42 | The sender end of a channel. Messages (e.g., decryption shares) to other nodes are to be sent trough this channel. 43 | - key: 44 | Of type `Arc`, defined in `../orchestration/src/types.rs`. 45 | The secret key and public keys, of type `schemes::keys::PrivateKey` and `schemes::keys::PublicKey` respectively, as accessible as `key.sk` and `key.sk.get_public_key`. 46 | The threshold is also accessible as `key.sk.get_threshold()`. 47 | 48 | ## Protocol messages 49 | 50 | Each protocol implementation is responsible for defining its message types in `src\\message_types.rs`, 51 | and for implementing two functions for each message type, 52 | `try_from_bytes()`and `to_net_message()`. 53 | For example, the `ThresholdCipherProtocol` uses a single message type, called `DecryptionShareMessage`, 54 | defined in `src\threshold_cipher\message_types.rs`. 55 | 56 | The interface between the network and a protocol is the following. 57 | A protocol instance receives on `chan_in` incoming messages as `Vec` and sends on `chan_out` outgoing 58 | messages of type `NetMessage` (this type is defined in the `network` crate, see the corresponding README). 59 | 60 | - `try_from_bytes()`: Takes a `Vec` and returns an instance of the message type, if the 61 | bytes can be deserialized to that message type. 62 | It is called by the protocol whenever a message is received. The idea is that the protocol calls 63 | `try_from_bytes()` on each message type. The protocol can then handle each message according to its specifications. 64 | Importantly, as the protocol knows the type of the incoming message, it knows whether it was delivered in total order or not. 65 | - `to_net_message()`: It returns a `NetMessage` and is called when a protocol wants to send a message. 66 | This function must set the `is_total_order` field of `NetMessage` to `true` if the protocol requires 67 | the corresponding message to be sent through the total-order channel. 68 | -------------------------------------------------------------------------------- /src/network/src/types/message.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize, Deserialize}; 2 | 3 | 4 | #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] 5 | pub enum Channel{ 6 | #[default] 7 | Gossip, 8 | TOB, 9 | PointToPoint { 10 | receiver_id: Vec, 11 | } 12 | } 13 | 14 | 15 | /// NetMessageMetadata incapsulates the information for handling the transmission of the message. 16 | /// Each message needs to specify the sender_id so that at the protocol layer it can be checked if 17 | /// the sender_id matched the share_id of the piece of information received. 18 | #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] 19 | pub struct NetMessageMetadata{ 20 | sender_id: u16, 21 | channel: Channel, 22 | } 23 | 24 | impl NetMessageMetadata{ 25 | pub fn new(channel: Channel) -> Self { 26 | NetMessageMetadata { 27 | sender_id: 0, 28 | channel: channel, 29 | } 30 | } 31 | 32 | pub fn set_sender(&mut self, sender_id: u16){ 33 | self.sender_id = sender_id; 34 | } 35 | 36 | pub fn get_sender(&self) -> u16 { 37 | return self.sender_id 38 | } 39 | 40 | pub fn get_channel(&self) -> &Channel{ 41 | return &self.channel 42 | } 43 | } 44 | 45 | 46 | //ROSE: Every message should have the sender id. The sernder_id is authenticated by the network layer and is needed by the protocol layer to check the info 47 | // inside the message_data 48 | 49 | // At an high level we want the NetMessage to contain just the instance_id, metadata, and message_data. 50 | // The instance_id is used by the orchestration logic of the core layer to decide to which protocol execution deliver the message 51 | // OBSV: Can an adversary mess up with the instance ids? If we add authentication NO. 52 | // The metadata should be used by the network layer to decide how to send the message, to add the signature and optionally encrypt. 53 | // We also need a mechanism to signal if a TOB channel is available or not and in case change the behavior of a protocol accordingly, or 54 | // deny it completely. 55 | // The message_data field is a vector of bytes with no meaning for the network layer. 56 | #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] 57 | pub struct NetMessage { 58 | instance_id: String, 59 | metadata: NetMessageMetadata, 60 | message_data: Vec, 61 | } 62 | 63 | 64 | impl NetMessage { 65 | pub fn new(instance_id: String, metadata: NetMessageMetadata, message_data: Vec)->NetMessage{ 66 | return NetMessage { 67 | instance_id, 68 | metadata, 69 | message_data, 70 | } 71 | } 72 | 73 | pub fn get_instace_id(&self) -> &String { 74 | return &self.instance_id 75 | } 76 | 77 | pub fn get_metadata(&self) -> &NetMessageMetadata{ 78 | return &self.metadata 79 | } 80 | 81 | pub fn get_message_data(&self) -> &Vec{ 82 | return &self.message_data 83 | } 84 | 85 | 86 | } 87 | impl From for Vec { 88 | fn from(net_message: NetMessage) -> Self { 89 | // serde_json::to_string(&p2p_message).unwrap().as_bytes().to_vec() 90 | serde_json::to_string(&net_message).expect("Error in From for Vec").into_bytes() 91 | } 92 | } 93 | impl From> for NetMessage { 94 | fn from(vec: Vec) -> Self { 95 | serde_json::from_str::(&String::from_utf8(vec).expect("Error in From> for NetMessage")).unwrap() 96 | } 97 | } -------------------------------------------------------------------------------- /src/utils/src/thetacli/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{Args, Parser, Subcommand}; 2 | 3 | #[derive(Parser, Debug)] 4 | #[command(version = "1.0", about, long_about = None)] 5 | #[command(propagate_version = true)] 6 | pub struct ThetaCliArgs { 7 | #[command(subcommand)] 8 | pub command: Commands, 9 | } 10 | 11 | #[derive(Subcommand, Debug)] 12 | pub enum Commands { 13 | /// Locally generate keys for threshold schemes 14 | Keygen(KeyGenArgs), 15 | /// Encrypt data using threshold encryption 16 | Enc(EncArgs), 17 | /// Verify threshold signatures 18 | Verify(VerifyArgs), 19 | /// Manipulate keystores 20 | Keystore(KeystoreArgs), 21 | } 22 | 23 | #[derive(Args, Debug)] 24 | pub struct KeyGenArgs { 25 | #[arg( 26 | short, 27 | help = "Threshold (minimum number of parties that need to collaborate)" 28 | )] 29 | pub k: u16, 30 | #[arg(short, help = "Number of parties")] 31 | pub n: u16, 32 | #[arg( 33 | short, 34 | long, 35 | help = "A list of comma separated elements of the format 'scheme-group', where 'scheme' is one of the following:\n\t encryption schemes: sg02, bz03\n\t signature schemes: bls04, frost, sh00\n\t coin schemes: cks05\nand 'group' is one of\n\t 'bls12381', 'bn254', 'ed25519', 'rsa512', 'rsa1024', 'rsa2048', 'rsa4096'.\nexample: sg02-bls12381,bz03-ed25519. \nA single string 'all' should be used to create all possible keys." 36 | )] 37 | pub subjects: String, 38 | #[arg(short, long, help = "Directory to store the generated keys in")] 39 | pub output: String, 40 | #[arg( 41 | long, 42 | help = "Option to create a completely new set of keys, overwriting the chosen keyfile if it already existed", 43 | default_value_t = false 44 | )] 45 | pub new: bool, 46 | } 47 | #[derive(Args, Debug)] 48 | pub struct EncArgs { 49 | #[arg(short, long, help = "The path to the input file")] 50 | pub infile: Option, 51 | #[arg(long, help = "The path to the public key file")] 52 | pub pubkey: Option, 53 | #[arg(long, help = "The path to the keystore")] 54 | pub keystore: Option, 55 | #[arg(short, long, help = "The key id")] 56 | pub key_id: Option, 57 | #[arg(short, long, help = "The encryption label")] 58 | pub label: String, 59 | #[arg(short, long, help = "The output file (use - for stdout)")] 60 | pub output: String, 61 | } 62 | 63 | #[derive(Args, Debug)] 64 | pub struct VerifyArgs { 65 | #[arg(short, long, help = "The path to the file containing the message")] 66 | pub message_path: String, 67 | #[arg(short, long, help = "The path to the file containing the signature")] 68 | pub signature_path: String, 69 | #[arg(long, help = "The path to the public key file")] 70 | pub pubkey: Option, 71 | #[arg(long, help = "The path to the keystore")] 72 | pub keystore: Option, 73 | #[arg(short, long, help = "The key id")] 74 | pub key_id: Option, 75 | } 76 | 77 | #[derive(Args, Debug)] 78 | pub struct KeystoreArgs { 79 | #[arg(help = "The action to perform")] 80 | pub action: String, 81 | #[arg(help = "The path to the keystore")] 82 | pub keystore: String, 83 | #[arg( 84 | long, 85 | help = "The address of the network node (example https://127.0.0.1:1234)" 86 | )] 87 | pub address: Option, 88 | #[arg( 89 | long, 90 | help = "Option to overwrite the existing keystore", 91 | default_value_t = false 92 | )] 93 | pub new: bool, 94 | #[arg(long, help = "Path to input key file")] 95 | pub input: Option, 96 | } 97 | -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_cipher/message_types.rs: -------------------------------------------------------------------------------- 1 | use log::{error, info, warn}; 2 | use serde::{Deserialize, Serialize}; 3 | use theta_network::types::message::{Channel, NetMessage, NetMessageMetadata}; 4 | use theta_schemes::interface::{DecryptionShare, Serializable}; 5 | 6 | use crate::interface::{ProtocolError, ProtocolMessageWrapper}; 7 | 8 | // To implement here a serialization that doesn't conflict with the one present at the scheme layer (based on rasn?) 9 | // we can have a generic bytevector already in the message and serialize and deserialize here into the specific types required by the protocol. 10 | // if we absract these steps here the protocol will not care about serializaion/deserialization details. 11 | #[derive(Serialize, Deserialize, Clone)] 12 | pub struct DecryptionShareMessage { 13 | share: DecryptionShare, 14 | sender_id: u16 15 | } 16 | 17 | impl DecryptionShareMessage { 18 | pub fn new(share: DecryptionShare) -> Self{ 19 | DecryptionShareMessage{ 20 | share, 21 | sender_id: 0 22 | } 23 | } 24 | 25 | pub fn get_share(&self) -> &DecryptionShare { 26 | &self.share 27 | } 28 | 29 | pub fn set_sender_id(&mut self, sender_id: u16){ 30 | self.sender_id = sender_id; 31 | } 32 | 33 | pub fn get_sender_id(&self) -> u16 { 34 | return self.sender_id 35 | } 36 | } 37 | 38 | //Here define an enum of possible messages used in the protocol 39 | //In the case of the cipher and all the non-interactive one round protocol here we will have just one value 40 | //for more complex protocol this is not true 41 | #[derive(Serialize, Deserialize, Clone)] 42 | pub enum DecryptionMessage { 43 | ShareMessage(DecryptionShareMessage), 44 | Default, 45 | } 46 | 47 | impl Default for DecryptionMessage { 48 | fn default() -> Self { 49 | DecryptionMessage::Default 50 | } 51 | } 52 | 53 | //consider that in protocols like frost you might have different kind of messages that needs the conversion 54 | //for the serialization 55 | 56 | impl ProtocolMessageWrapper for DecryptionMessage { 57 | fn unwrap(wrapped: NetMessage) -> Result, ProtocolError> { 58 | let bytes = wrapped.get_message_data().to_owned(); 59 | let result = serde_json::from_str::( 60 | &String::from_utf8(bytes).expect("Error serializing the JSON"), 61 | ); 62 | match result { 63 | Ok(message) => return Ok(Box::new(message)), 64 | Err(_) => { 65 | return Err(ProtocolError::InternalError); //To change the type of error 66 | } 67 | }; 68 | } 69 | 70 | ///wrap() provides the logic to correctly create a NetMessage and add the necessary metadata for the medium to use for the delivery. 71 | // TODO: at this level we are not able to distiguish between the messages (if there is more than one). 72 | // These functions (or at least wrap) needs to be implemented for each value of the enum 73 | fn wrap(&self, instance_id: &String) -> Result { 74 | let message_data = serde_json::to_string(&self) 75 | .expect("Error in serializing DecryptionShareMessage for Vec") 76 | .into_bytes(); 77 | let metadata = NetMessageMetadata::new(Channel::Gossip); 78 | let net_message = NetMessage::new(instance_id.clone(), metadata, message_data); 79 | return Ok(net_message); 80 | } 81 | 82 | fn is_default(&self) -> bool { 83 | match self { 84 | DecryptionMessage::Default => true, 85 | _ => false 86 | } 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/secp256k1/rom.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /* Fixed Data in ROM - Field and Curve parameters */ 21 | 22 | use crate::arch::Chunk; 23 | use crate::secp256k1::big::NLEN; 24 | 25 | // Base Bits= 56 26 | // secp256k1 modulus 27 | pub const MODULUS: [Chunk; NLEN] = [ 28 | 0xFFFFFEFFFFFC2F, 29 | 0xFFFFFFFFFFFFFF, 30 | 0xFFFFFFFFFFFFFF, 31 | 0xFFFFFFFFFFFFFF, 32 | 0xFFFFFFFF, 33 | ]; 34 | pub const ROI: [Chunk; NLEN] = [ 35 | 0xFFFFFEFFFFFC2E, 36 | 0xFFFFFFFFFFFFFF, 37 | 0xFFFFFFFFFFFFFF, 38 | 0xFFFFFFFFFFFFFF, 39 | 0xFFFFFFFF, 40 | ]; 41 | pub const R2MODP: [Chunk; NLEN] = [0xA1000000000000, 0x7A2000E90, 0x1, 0x0, 0x0]; 42 | pub const MCONST: Chunk = 0x38091DD2253531; 43 | pub const SQRTM3:[Chunk;NLEN]=[0x8D27AE1CD5F852,0x6D15DA14ECD47D,0xC2A797962CC61F,0x3507F1DF233770,0xA2D2BA9]; 44 | 45 | // secp256k1 curve 46 | pub const CURVE_COF_I: isize = 1; 47 | pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0]; 48 | pub const CURVE_B_I: isize = 7; 49 | pub const CURVE_B: [Chunk; NLEN] = [0x7, 0x0, 0x0, 0x0, 0x0]; 50 | pub const CURVE_ORDER: [Chunk; NLEN] = [ 51 | 0xD25E8CD0364141, 52 | 0xDCE6AF48A03BBF, 53 | 0xFFFFFFFFFEBAAE, 54 | 0xFFFFFFFFFFFFFF, 55 | 0xFFFFFFFF, 56 | ]; 57 | pub const CURVE_GX: [Chunk; NLEN] = [ 58 | 0xF2815B16F81798, 59 | 0xFCDB2DCE28D959, 60 | 0x95CE870B07029B, 61 | 0xF9DCBBAC55A062, 62 | 0x79BE667E, 63 | ]; 64 | pub const CURVE_GY: [Chunk; NLEN] = [ 65 | 0x47D08FFB10D4B8, 66 | 0xB448A68554199C, 67 | 0xFC0E1108A8FD17, 68 | 0x26A3C4655DA4FB, 69 | 0x483ADA77, 70 | ]; 71 | pub const CURVE_HTPC:[Chunk;NLEN]=[0xC813789E8624AA,0xCA45C23F508ECD,0x640A39CD8BBBFD,0x813FFE30F4D5B4,0xCCE8E9E8]; 72 | pub const CURVE_AD:[Chunk;NLEN]=[0x5447C01A444533,0xD363CB6F0E5D40,0x58F0F5D272E953,0xDD661ADCA08A55,0x3F8731AB]; 73 | pub const CURVE_BD:[Chunk;NLEN]=[0x6EB,0x0,0x0,0x0,0x0]; 74 | pub const PC:[[Chunk;NLEN];13]=[[0x38E38DAAAAA88C,0x8E38E38E38E38E,0xE38E38E38E38E3,0x38E38E38E38E38,0x8E38E38E],[0xCBD0B53D9DD262,0x6144037C40314E,0xDECA25CAECE450,0x23F234E6E2A413,0x534C328D],[0xFF1044F17C6581,0xD2FC0BF63B92DF,0xCEA7FD44C5D595,0xBC321D5B9F315,0x7D3D4C8],[0x38E38DAAAAA8C7,0x8E38E38E38E38E,0xE38E38E38E38E3,0x38E38E38E38E38,0x8E38E38E],[0x2A56612A8C6D14,0x6B641F5E41BBC5,0xD51B54225406D3,0x4383DC1DF7C4B2,0xEDADC6F6],[0xE6B745781EB49B,0x409542F8487D9F,0xCBB7B640DD86CD,0x3D94918A9CA34C,0xD3577119],[0xBDA12F38E38D84,0x2F684BDA12F684,0x4BDA12F684BDA1,0x12F684BDA12F68,0x2F684BDA],[0x65E85A9ECEE931,0x30A201BE2018A7,0xEF6512E5767228,0x91F91A73715209,0x29A61946],[0xFC90FC201D71A3,0xB046D686DA6FDF,0x4B12A0A6D5647A,0xD5CB7C0FA9D0A5,0xC75E0C32],[0x2F684B8E38E23C,0x4BDA12F684BDA1,0x12F684BDA12F68,0x84BDA12F684BDA,0x4BDA12F6],[0xBF8192BFD2A76F,0x21162F0D6299A7,0x3FA8FE337E0A3D,0x6545CA2CF3A70C,0x6484AA71],[0xB425D2685C2573,0xC1BFC8E8D978DF,0x632722C2989467,0xB8BDB49FD5E9E6,0x7A06534B],[0xFFFFFEFFFFF93B,0xFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFF,0xFFFFFFFF]]; 75 | 76 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Thetacrypt - Threshold Cryptography Distributed Service in Rust 2 | 3 | Thetacrypt is a WIP codebase that aims at providing **threshold cryptography** as a service. 4 | 5 | - To dive into the details of the architecture of our service explore the `src` directory. 6 | - To try a quick start and immediately explore the functionalities offered by Thetacrypt, check the `demo` directory. 7 | - To learn more about threshold cryptography and its theoretical background, remain on this page. 8 | 9 | ## Theoretical background 10 | 11 | ### What is threshold cryptography? 12 | 13 | Threshold cryptography defines protocols to enhance the security of a cryptographic scheme by distributing the trust among a group of parties. 14 | Typically, it is used for sharing a secret across a predefined number of nodes so as to obtain fault-tolerance for a subset, 15 | or *threshold*, of them. 16 | More formally, a threshold cryptosystem is defined by a fixed number of parties $P = \{P_1, \dots, P_n\}$, who need to collaborate to perform a cryptographic operation such that at least a threshold of them, $(t+1)$-out-of- $n$, are able to successfully terminate, but $t$ will learn anything about the shared secret. 17 | This is achieved by using *Shamir's secret sharing*, i.e. a technique based on *polynomial interpolation* that enables the reconstruction 18 | of a polynomial of degree $t$ with at least $t+1$ points. 19 | 20 | 21 | The generation and distribution of a secret $s$ is performed, in the easiest setting, by a trusted dealer $D$ $\notin P$. The dealer chooses at random the coefficients 22 | $\{a_1, \dots, a_t\}$ and defines the polynomial: $p(x) = s + a_1 x + \dots + a_t x^t$. The polynomial has a degree at most $t$ and its evaluation 23 | in $p(0)$ is the secret. The polynomial will be uniquely determined by $t+1$ point. 24 | 25 | Threshold cryptosystems are known for public-key schemes only, where applying secret sharing is possible thanks to the algebraic assumption used in such schemes. 26 | 27 | ## Implemented Schemes and References 28 | 29 | | Scheme Name | Scheme Type | Reference | 30 | |--------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 31 | | SG02 | Cryptosystem | [Securing Threshold Cryptosystems against Chosen Ciphertext Attack](https://link.springer.com/content/pdf/10.1007/s00145-001-0020-9.pdf) (ZK-based) | 32 | | BZ03 | Cryptosystem | [Simple and Efficient Threshold Cryptosystem from the Gap Diffie-Hellman Group](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1258486) (Pairing-based) | 33 | | BLS04 | Signature | [Short Signatures from the Weil Pairing](https://www.iacr.org/archive/asiacrypt2001/22480516.pdf) (Pairing-based) | 34 | | FROST | Signature | [FROST: Flexible Round-Optimized Schnorr Threshold Signatures](https://eprint.iacr.org/2020/852.pdf) (ZK-based) | 35 | | SH00 | Signature | [Practical Threshold Signatures](https://www.iacr.org/archive/eurocrypt2000/1807/18070209-new.pdf) (Threshold RSA) | 36 | | CKS05 | Coin-flip | [Random Oracles in Constantinople: Practical Asynchronous Byzantine Agreement Using Cryptography](https://link.springer.com/content/pdf/10.1007/s00145-005-0318-0.pdf) (ZK-based) | 37 | 38 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/group.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use rasn::AsnType; 3 | use std::borrow::Borrow; 4 | use std::mem; 5 | use std::{fmt::Debug, mem::ManuallyDrop}; 6 | use theta_derive::GroupOperations; 7 | 8 | use theta_proto::scheme_types::Group; 9 | 10 | use crate::integers::sizedint::SizedBigInt; 11 | use crate::{ 12 | groups::ec::{bls12381::Bls12381, bn254::Bn254, ed25519::Ed25519}, 13 | interface::SchemeError, 14 | rand::RNG, 15 | scheme_types_impl::GroupDetails, 16 | }; 17 | 18 | /* Enum representing the implemented groups (incl. order and whether they support pairings) stored 19 | in proto folder. Each group has a code (8-bit unsigned integer) that's used to encode the 20 | group when serializing group elements. 21 | 22 | TODO: change code to standard way of encoding EC groups */ 23 | 24 | /* GroupElement is the representation of a single group element, use this for computation. It is a wrapper 25 | around the EC implementation Miracl Core provides to allow for curve-agnosic implementations of schemes. 26 | */ 27 | #[repr(C)] 28 | #[rasn(enumerated)] 29 | #[derive(Debug, Clone, AsnType, GroupOperations)] 30 | pub enum GroupElement { 31 | #[supports_pairings] 32 | Bls12381(Bls12381), 33 | #[supports_pairings] 34 | Bn254(Bn254), 35 | #[no_pairings] 36 | Ed25519(Ed25519), 37 | } 38 | 39 | /* 40 | Objects of type GroupElement automatically implement the following trait thanks to procedural macros 41 | */ 42 | pub trait GroupOperations { 43 | /* return identity of given group */ 44 | fn identity(group: &Group) -> Self; 45 | 46 | /* check whether two group elements belong to the same group */ 47 | fn cmp_group(&self, other: &Self) -> bool; 48 | 49 | /* check whether group element belongs to certain group */ 50 | fn is_type(&self, group: &Group) -> bool; 51 | 52 | /* get group from group element */ 53 | fn get_group(&self) -> &Group; 54 | 55 | /* create new group element */ 56 | fn new(group: &Group) -> Self; 57 | 58 | /* if the curve has an extension field, create element in extension field */ 59 | fn new_ecp2(group: &Group) -> Self; 60 | 61 | /* calculate pairing between self and y (panics if group does not support pairings!) */ 62 | fn pair(&self, y: &Self) -> Self; 63 | 64 | /* returns true if pair(x,y) == pair(z,w) (panics if group does not support pairings!)*/ 65 | fn ddh( 66 | x: &GroupElement, 67 | y: &GroupElement, 68 | z: &GroupElement, 69 | w: &GroupElement, 70 | ) -> Result; 71 | 72 | /* generate a new group element from a hash (given as a byte array) -> not supported by ed25519! */ 73 | fn new_hash(group: &Group, hash: &[u8]) -> Self; 74 | 75 | /* returns g^y where g is the generator of selected group */ 76 | fn new_pow_big(group: &Group, y: &SizedBigInt) -> Self; 77 | 78 | /* returns g^y where g is the generator of the extension field of selected group */ 79 | fn new_pow_big_ecp2(group: &Group, y: &SizedBigInt) -> Self; 80 | 81 | /* returns random element in group */ 82 | fn new_rand(group: &Group, rng: &mut RNG) -> Self; 83 | 84 | /* returns self*y */ 85 | fn mul(&self, y: &Self) -> Self; 86 | 87 | /* returns self/y */ 88 | fn div(&self, y: &Self) -> Self; 89 | 90 | /* returns self^y */ 91 | fn pow(&self, y: &SizedBigInt) -> Self; 92 | 93 | /* get order of group element */ 94 | fn get_order(&self) -> SizedBigInt; 95 | 96 | /* encode group element in bytes (big endian) */ 97 | fn to_bytes(&self) -> Vec; 98 | 99 | /* convert group element to hex string (big endian) */ 100 | fn to_string(&self) -> String; 101 | 102 | /* decode group element from bytes (big endian) */ 103 | fn from_bytes(bytes: &[u8], group: &Group, i: Option) -> Self; 104 | } 105 | -------------------------------------------------------------------------------- /src/core/schemes/src/bin/schemes_example.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(clippy::many_single_char_names)] 3 | #![allow(clippy::zero_prefixed_literal)] 4 | #![allow(dead_code)] 5 | 6 | use std::time::Instant; 7 | 8 | use std::fmt::Write; 9 | use theta_proto::scheme_types::Group; 10 | use theta_schemes::interface::ThresholdScheme; 11 | use theta_schemes::interface::{ThresholdCipher, ThresholdCipherParams}; 12 | use theta_schemes::keys::key_generator::KeyGenerator; 13 | use theta_schemes::rand::{RngAlgorithm, RNG}; 14 | use theta_schemes::util::{hex2string, printbinary}; 15 | 16 | fn main() { 17 | const K: usize = 30; // threshold 18 | const N: usize = 50; // total number of secret shares 19 | 20 | // prepare message and label 21 | let plaintext = "This is a test message! "; 22 | let msg: Vec = String::from(plaintext).as_bytes().to_vec(); 23 | let label = b"Label"; 24 | 25 | println!("K: {} N: {}", K, N); 26 | println!("Message: {}", plaintext); 27 | 28 | // perform threshold encryption using Sg02 scheme 29 | println!("\n--Sg02 Threshold Cipher--"); 30 | 31 | // generate secret shares for Sg02 scheme over Bls12381 curve 32 | let now = Instant::now(); 33 | let sk = KeyGenerator::generate_keys( 34 | K, 35 | N, 36 | &mut RNG::new(RngAlgorithm::OsRng), 37 | &ThresholdScheme::Sg02, 38 | &Group::Bls12381, 39 | &Option::None, 40 | ) 41 | .unwrap(); 42 | let elapsed_time = now.elapsed().as_millis(); 43 | println!("[{}ms]\t{} Keys generated", K, elapsed_time); 44 | 45 | // initialize new random number generator 46 | let mut params = ThresholdCipherParams::new(); 47 | 48 | // a public key is stored inside each secret share, so those can be used for encryption 49 | let now = Instant::now(); 50 | let ciphertext = 51 | ThresholdCipher::encrypt(&msg, label, &sk[0].get_public_key(), &mut params).unwrap(); 52 | let encrypt_time = now.elapsed().as_millis(); 53 | println!("[{}ms]\tMessage encrypted", encrypt_time); 54 | 55 | let mut s = String::with_capacity(25); 56 | write!(&mut s, "[{}ms]\tCiphertext: ", encrypt_time).expect("error"); 57 | printbinary(&ciphertext.get_ctxt(), Some(s.as_str())); 58 | 59 | // check whether ciphertext is valid 60 | let now = Instant::now(); 61 | let valid = ThresholdCipher::verify_ciphertext(&ciphertext, &sk[0].get_public_key()).unwrap(); 62 | let elapsed_time = now.elapsed().as_millis(); 63 | 64 | // create decryption shares and verify them 65 | let mut shares = Vec::new(); 66 | let mut share_gen_time = 0; 67 | let mut share_verify_time = 0; 68 | 69 | println!("[*] Generating and validating shares..."); 70 | 71 | for i in 0..K { 72 | let now = Instant::now(); 73 | shares.push( 74 | ThresholdCipher::partial_decrypt(&ciphertext, &sk[i as usize], &mut params).unwrap(), 75 | ); 76 | share_gen_time += now.elapsed().as_millis(); 77 | 78 | let now = Instant::now(); 79 | let valid = ThresholdCipher::verify_share( 80 | &shares[i as usize], 81 | &ciphertext, 82 | &sk[0].get_public_key(), 83 | ) 84 | .unwrap(); 85 | share_verify_time += now.elapsed().as_millis(); 86 | } 87 | println!("[{}ms]\t{} Shares generated", share_gen_time, K); 88 | println!("[{}ms]\t{} Shares validated", share_verify_time, K); 89 | 90 | println!("[*] Decrypting..."); 91 | // assemble decryption shares to restore original message 92 | let now = Instant::now(); 93 | let msg = ThresholdCipher::assemble(&shares, &ciphertext).unwrap(); 94 | let elapsed_time = now.elapsed().as_millis(); 95 | 96 | println!( 97 | "[{}ms]\tMessage decrypted: {}", 98 | elapsed_time, 99 | hex2string(&msg) 100 | ); 101 | } 102 | -------------------------------------------------------------------------------- /src/core/schemes/src/groups/group_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::groups::ec::bls12381::Bls12381; 2 | use crate::groups::group::GroupElement; 3 | use crate::integers::sizedint::SizedBigInt; 4 | use crate::rand::RNG; 5 | use rand::Rng; 6 | use theta_proto::scheme_types::Group; 7 | 8 | use crate::groups::group::GroupOperations; 9 | static GROUP: Group = Group::Bls12381; 10 | 11 | #[test] 12 | fn test_mul() { 13 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 14 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 15 | let int8: SizedBigInt = SizedBigInt::new_int(&GROUP, 8); 16 | 17 | let a = GroupElement::new_pow_big(&GROUP, &int3); 18 | let b = GroupElement::new_pow_big(&GROUP, &int5); 19 | let c = a.mul(&b); 20 | let d = GroupElement::new_pow_big(&GROUP, &int8); 21 | 22 | assert!(c.eq(&d)); 23 | 24 | let c = a.mul(&b).mul(&b).mul(&a); 25 | let d = GroupElement::new_pow_big(&GROUP, &SizedBigInt::new_int(&GROUP, 16)); 26 | assert!(c.eq(&d)); 27 | } 28 | 29 | #[test] 30 | fn test_ecp2_mul() { 31 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 32 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 33 | let int8: SizedBigInt = SizedBigInt::new_int(&GROUP, 8); 34 | 35 | let a = GroupElement::new_pow_big_ecp2(&GROUP, &int3); 36 | let b = GroupElement::new_pow_big_ecp2(&GROUP, &int5); 37 | let c = a.mul(&b); 38 | let d = GroupElement::new_pow_big_ecp2(&GROUP, &int8); 39 | 40 | assert!(c.eq(&d)); 41 | 42 | let c = a.mul(&b).mul(&b).mul(&a); 43 | let d = GroupElement::new_pow_big_ecp2(&GROUP, &SizedBigInt::new_int(&GROUP, 16)); 44 | assert!(c.eq(&d)); 45 | } 46 | 47 | #[test] 48 | fn test_div() { 49 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 50 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 51 | let int8: SizedBigInt = SizedBigInt::new_int(&GROUP, 8); 52 | 53 | let a = GroupElement::new_pow_big(&GROUP, &int8); 54 | let b = GroupElement::new_pow_big(&GROUP, &int5); 55 | let c = a.div(&b); 56 | let d = GroupElement::new_pow_big(&GROUP, &int3); 57 | 58 | assert!(c.eq(&d)); 59 | } 60 | 61 | #[test] 62 | fn test_div_ecp2() { 63 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 64 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 65 | let int8: SizedBigInt = SizedBigInt::new_int(&GROUP, 8); 66 | 67 | let a = GroupElement::new_pow_big_ecp2(&GROUP, &int8); 68 | let b = GroupElement::new_pow_big_ecp2(&GROUP, &int5); 69 | let c = a.div(&b); 70 | let d = GroupElement::new_pow_big_ecp2(&GROUP, &int3); 71 | 72 | assert!(c.eq(&d)); 73 | } 74 | 75 | #[test] 76 | fn test_pow() { 77 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 78 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 79 | let int15: SizedBigInt = SizedBigInt::new_int(&GROUP, 15); 80 | 81 | let a = GroupElement::new_pow_big(&GROUP, &int3); 82 | let b = a.pow(&int5); 83 | let c = GroupElement::new_pow_big(&GROUP, &int15); 84 | 85 | assert!(b.eq(&c)); 86 | } 87 | 88 | #[test] 89 | fn test_pow_ecp2() { 90 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 91 | let int5: SizedBigInt = SizedBigInt::new_int(&GROUP, 5); 92 | let int15: SizedBigInt = SizedBigInt::new_int(&GROUP, 15); 93 | 94 | let a = GroupElement::new_pow_big_ecp2(&GROUP, &int3); 95 | let b = a.pow(&int5); 96 | let c = GroupElement::new_pow_big_ecp2(&GROUP, &int15); 97 | 98 | assert!(b.eq(&c)); 99 | } 100 | 101 | #[test] 102 | fn test_new_pow() { 103 | let int3: SizedBigInt = SizedBigInt::new_int(&GROUP, 3); 104 | let a = GroupElement::new_pow_big(&GROUP, &int3); 105 | let b = GroupElement::new(&GROUP).pow(&int3); 106 | 107 | assert!(a.eq(&b)); 108 | 109 | let a = GroupElement::new_pow_big_ecp2(&GROUP, &int3); 110 | let b = GroupElement::new_ecp2(&GROUP).pow(&int3); 111 | 112 | assert!(a.eq(&b)); 113 | } 114 | 115 | #[test] 116 | fn test_schnorr() { 117 | let int2: SizedBigInt = SizedBigInt::new_int(&GROUP, 2); 118 | 119 | let a = GroupElement::new_pow_big(&GROUP, &int2); 120 | 121 | let res = a.pow(&int2).div(&a.pow(&int2)); 122 | 123 | assert!(res.eq(&GroupElement::identity(&GROUP))); 124 | } 125 | -------------------------------------------------------------------------------- /src/core/schemes/src/keys/key_store_tests.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fs::remove_file, path::PathBuf}; 2 | 3 | use base64::{engine::general_purpose, Engine}; 4 | use mcore::hash256::HASH256; 5 | use theta_proto::scheme_types::{Group, ThresholdScheme}; 6 | 7 | use crate::{ 8 | interface::{Serializable, ThresholdCipherParams}, 9 | rand::{RngAlgorithm, RNG}, 10 | }; 11 | 12 | use super::{ 13 | key_generator::KeyGenerator, 14 | key_store::KeyStore, 15 | keys::{calc_key_id, key2id, PrivateKeyShare}, 16 | }; 17 | 18 | #[test] 19 | pub fn test_adding_and_retrieving_keys() { 20 | let keypair0 = KeyGenerator::generate_keys( 21 | 3, 22 | 5, 23 | &mut RNG::new(crate::rand::RngAlgorithm::OsRng), 24 | &ThresholdScheme::Sg02, 25 | &Group::Bls12381, 26 | &Option::None, 27 | ) 28 | .unwrap(); 29 | 30 | let mut keystore: KeyStore = KeyStore::new(); 31 | let result = keystore.insert_private_key(keypair0[0].clone()); 32 | assert!(result.is_ok(), "could not add key pair"); 33 | let id = result.unwrap(); 34 | 35 | let keypair1 = KeyGenerator::generate_keys( 36 | 3, 37 | 5, 38 | &mut RNG::new(crate::rand::RngAlgorithm::OsRng), 39 | &ThresholdScheme::Sg02, 40 | &Group::Bls12381, 41 | &Option::None, 42 | ) 43 | .unwrap(); 44 | 45 | let result = keystore.insert_private_key(keypair1[0].clone()); 46 | assert!(result.is_ok(), "could not add second key pair"); 47 | 48 | let retrieved_key = keystore.get_key_by_id(&id); 49 | assert!(retrieved_key.is_ok()); 50 | assert_eq!( 51 | retrieved_key.as_ref().unwrap().sk.as_ref().unwrap(), 52 | &keypair0[0] 53 | ); 54 | } 55 | 56 | // it should not be possible to add multiple private key shares belonging to the same public key 57 | #[test] 58 | pub fn test_cannot_add_multiple_private_key_ids() { 59 | let keypair = KeyGenerator::generate_keys( 60 | 3, 61 | 5, 62 | &mut RNG::new(crate::rand::RngAlgorithm::OsRng), 63 | &ThresholdScheme::Sg02, 64 | &Group::Bls12381, 65 | &Option::None, 66 | ) 67 | .unwrap(); 68 | 69 | let mut keystore: KeyStore = KeyStore::new(); 70 | let result = keystore.insert_private_key(keypair[0].clone()); 71 | assert!(result.is_ok()); 72 | let key_id = result.unwrap(); 73 | let result = keystore.insert_private_key(keypair[1].clone()); 74 | assert!( 75 | result.is_err(), 76 | "could add second private key share to existing public key" 77 | ); 78 | } 79 | 80 | #[test] 81 | fn test_keychain_serialization() { 82 | let (key_chain, keys) = fill_key_chain(); 83 | 84 | key_chain 85 | .to_file("test_keychain_ser.txt") 86 | .expect("KeyStore::to_file returned Err"); 87 | let key_chain_unser = KeyStore::from_file(&PathBuf::from("test_keychain_ser.txt")) 88 | .expect("KeyStore::from_file returned Err"); 89 | let _ = remove_file("test_keychain_ser.txt"); 90 | 91 | assert_eq!(key_chain, key_chain_unser); 92 | } 93 | 94 | #[test] 95 | fn test_get_encryption_keys() { 96 | let (key_chain, keys) = fill_key_chain(); 97 | 98 | let encryption_keys = key_chain.get_encryption_keys(); 99 | assert!(encryption_keys.len() == 2); 100 | 101 | for (key_id, private_key) in keys.iter() { 102 | let key = encryption_keys 103 | .iter() 104 | .find(|&e| e.id == *key_id) 105 | .expect("Key with id {key_id} should be found."); 106 | assert!(key.sk.as_ref().unwrap().get_scheme() == ThresholdScheme::Sg02); 107 | assert!(Group::Bls12381.eq(key.sk.as_ref().unwrap().get_group())); 108 | assert!(private_key.eq(key.sk.as_ref().unwrap())); 109 | } 110 | } 111 | 112 | fn fill_key_chain() -> (KeyStore, HashMap) { 113 | let mut key_chain = KeyStore::new(); 114 | let mut keys: HashMap = HashMap::new(); 115 | for i in 0..2 { 116 | let sk_sg02_bls12381 = KeyGenerator::generate_keys( 117 | 3, 118 | 4, 119 | &mut RNG::new(RngAlgorithm::MarsagliaZaman), 120 | &ThresholdScheme::Sg02, 121 | &Group::Bls12381, 122 | &None, 123 | ) 124 | .expect("KeyGenerator::generate_keys returned Err"); 125 | 126 | let key_id = key2id(&sk_sg02_bls12381[0].get_public_key()); 127 | 128 | keys.insert(key_id.clone(), sk_sg02_bls12381[0].clone()); 129 | key_chain 130 | .insert_private_key(sk_sg02_bls12381[0].clone()) 131 | .unwrap(); 132 | } 133 | (key_chain, keys) 134 | } 135 | -------------------------------------------------------------------------------- /src/core/protocols/src/frost/tests.rs: -------------------------------------------------------------------------------- 1 | use log::info; 2 | use theta_schemes::{ 3 | dl_schemes::signatures::frost::{FrostOptions, FrostPrivateKey}, 4 | interface::{Group, Serializable, Signature, ThresholdScheme, ThresholdSignature}, 5 | keys::{key_generator::KeyGenerator, keys::PrivateKeyShare}, 6 | rand::{RngAlgorithm, RNG}, 7 | unwrap_enum_vec, 8 | }; 9 | 10 | use crate::{frost::protocol::FrostProtocol, interface::ThresholdRoundProtocol}; 11 | 12 | #[test] 13 | fn test_interface() { 14 | let k = 3; 15 | let n = 7; 16 | 17 | let keys = KeyGenerator::generate_keys( 18 | k, 19 | n, 20 | &mut RNG::new(RngAlgorithm::OsRng), 21 | &ThresholdScheme::Frost, 22 | &Group::Ed25519, 23 | &Option::None, 24 | ) 25 | .unwrap(); 26 | 27 | assert!(keys.len() == n); 28 | 29 | let msg = b"Test message!"; 30 | let pk = keys[0].get_public_key(); 31 | 32 | let mut instances = Vec::new(); 33 | 34 | for i in 0..n { 35 | let instance: FrostProtocol = FrostProtocol::new( 36 | keys[i].clone().into(), 37 | msg, 38 | b"label", 39 | FrostOptions::NoPrecomputation, 40 | Option::None, 41 | ); 42 | instances.push(instance); 43 | } 44 | 45 | let signer_group = instances[0].get_signer_group(); 46 | 47 | 48 | let mut messages = Vec::new(); 49 | 50 | while !instances[0].is_ready_to_finalize() { 51 | for i in 0..n { 52 | messages.push(instances[i].do_round().unwrap()); 53 | } 54 | println!("Round done"); 55 | println!("Messages: {:?}", messages); 56 | for i in 0..n { 57 | let mut j = 0; 58 | println!("start update for instance {}", i); 59 | while !instances[i].is_ready_for_next_round() { 60 | if signer_group.contains(&messages[j].id) { 61 | assert!(instances[i].update(messages[j].clone()).is_ok()); 62 | } 63 | j += 1; 64 | } 65 | println!("end update for instance {}", i); 66 | } 67 | 68 | messages.clear(); 69 | } 70 | 71 | let signature = instances[0].finalize().unwrap(); 72 | let result = Signature::from_bytes(&signature); 73 | 74 | match result { 75 | Ok(signature) => { 76 | assert!(ThresholdSignature::verify(&signature, &pk, msg).unwrap()); 77 | }, 78 | Err(e) => { 79 | println!("Error during update: {:?}", e); 80 | } 81 | } 82 | 83 | 84 | } 85 | 86 | #[test] 87 | fn test_private_key_serialization() { 88 | let keys = KeyGenerator::generate_keys( 89 | 3, 90 | 5, 91 | &mut RNG::new(RngAlgorithm::OsRng), 92 | &ThresholdScheme::Frost, 93 | &Group::Ed25519, 94 | &Option::None, 95 | ) 96 | .unwrap(); 97 | 98 | let bytes = keys[0].to_bytes(); 99 | assert!(bytes.is_ok()); 100 | let bytes = bytes.unwrap(); 101 | let key = PrivateKeyShare::from_bytes(&bytes); 102 | assert!(key.is_ok()); 103 | assert!(key.unwrap().eq(&keys[0])); 104 | } 105 | 106 | 107 | /* 108 | #[test] 109 | fn test_precomputation() { 110 | let k = 3; 111 | let n = 5; 112 | 113 | let keys = KeyGenerator::generate_keys( 114 | k, 115 | n, 116 | &mut RNG::new(RngAlgorithm::OsRng), 117 | &ThresholdScheme::Frost, 118 | &Group::Ed25519, 119 | &Option::None, 120 | ) 121 | .unwrap(); 122 | assert!(keys.len() == n); 123 | 124 | let msg = b"Test message!"; 125 | let pk = keys[0].get_public_key(); 126 | 127 | let mut instances = Vec::new(); 128 | 129 | for i in 0..k { 130 | let I = InteractiveThresholdSignature::new( 131 | &keys[i], 132 | msg, 133 | Some(ThresholdSignatureOptions::Frost( 134 | FrostOptions::Precomputation, 135 | )), 136 | ) 137 | .unwrap(); 138 | instances.push(I); 139 | } 140 | 141 | let mut round_results = Vec::new(); 142 | 143 | while !instances[0].is_finished() { 144 | for i in 0..k { 145 | round_results.push(instances[i].do_round().unwrap()); 146 | } 147 | 148 | for i in 0..k { 149 | let mut j = 0; 150 | while !instances[i].is_ready_for_next_round() { 151 | assert!(instances[i].update(&round_results[j]).is_ok()); 152 | j += 1; 153 | } 154 | } 155 | 156 | round_results.clear(); 157 | } 158 | 159 | let signature = instances[0].get_signature().unwrap(); 160 | assert!(ThresholdSignature::verify(&signature, &pk, msg).unwrap()); 161 | } 162 | */ 163 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/coins/cks05_tests.rs: -------------------------------------------------------------------------------- 1 | use super::cks05::*; 2 | use crate::keys::key_generator::KeyGenerator; 3 | use crate::{ 4 | groups::ec::bls12381::Bls12381, 5 | interface::{CoinShare, Serializable, ThresholdCoin}, 6 | keys::keys::PublicKey, 7 | rand::{RngAlgorithm, RNG}, 8 | util::printbinary, 9 | }; 10 | use theta_proto::scheme_types::{Group, ThresholdScheme}; 11 | 12 | #[test] 13 | fn test_key_generation() { 14 | let keys = KeyGenerator::generate_keys( 15 | 3, 16 | 5, 17 | &mut RNG::new(RngAlgorithm::OsRng), 18 | &ThresholdScheme::Cks05, 19 | &Group::Bls12381, 20 | &Option::None, 21 | ) 22 | .unwrap(); 23 | assert!(keys.len() == 5); 24 | } 25 | 26 | #[test] 27 | fn test_public_key_serialization() { 28 | let private_keys = KeyGenerator::generate_keys( 29 | 3, 30 | 5, 31 | &mut RNG::new(RngAlgorithm::OsRng), 32 | &ThresholdScheme::Cks05, 33 | &Group::Bls12381, 34 | &Option::None, 35 | ) 36 | .unwrap(); 37 | let public_key = private_keys[0].get_public_key(); 38 | assert!(private_keys.len() == 5); 39 | 40 | let public_key_encoded = public_key.to_bytes().unwrap(); 41 | let public_key_decoded = PublicKey::from_bytes(&public_key_encoded).unwrap(); 42 | assert!(public_key.eq(&public_key_decoded)); 43 | } 44 | 45 | #[test] 46 | fn test_share_creation() { 47 | let private_keys = KeyGenerator::generate_keys( 48 | 3, 49 | 5, 50 | &mut RNG::new(RngAlgorithm::OsRng), 51 | &ThresholdScheme::Cks05, 52 | &Group::Bls12381, 53 | &Option::None, 54 | ) 55 | .unwrap(); 56 | let name = b"Label"; 57 | let share = 58 | ThresholdCoin::create_share(name, &private_keys[0], &mut RNG::new(RngAlgorithm::OsRng)) 59 | .unwrap(); 60 | let valid = 61 | ThresholdCoin::verify_share(&share, name, &private_keys[0].get_public_key()).unwrap(); 62 | assert!(valid); 63 | } 64 | 65 | #[test] 66 | fn test_share_serialization() { 67 | let private_keys = KeyGenerator::generate_keys( 68 | 3, 69 | 5, 70 | &mut RNG::new(RngAlgorithm::OsRng), 71 | &ThresholdScheme::Cks05, 72 | &Group::Bls12381, 73 | &Option::None, 74 | ) 75 | .unwrap(); 76 | let name = b"Label"; 77 | let share = 78 | ThresholdCoin::create_share(name, &private_keys[0], &mut RNG::new(RngAlgorithm::OsRng)) 79 | .unwrap(); 80 | 81 | let share_encoded = share.to_bytes().unwrap(); 82 | let share_decoded = CoinShare::from_bytes(&share_encoded).unwrap(); 83 | 84 | assert!(share.eq(&share_decoded)); 85 | } 86 | 87 | #[test] 88 | fn test_full_scheme() { 89 | let keys = KeyGenerator::generate_keys( 90 | 3, 91 | 5, 92 | &mut RNG::new(RngAlgorithm::OsRng), 93 | &ThresholdScheme::Cks05, 94 | &Group::Bls12381, 95 | &Option::None, 96 | ) 97 | .unwrap(); 98 | let name = b"My Coin"; 99 | let mut shares = Vec::new(); 100 | 101 | for i in 0..5 { 102 | shares.push( 103 | ThresholdCoin::create_share( 104 | name, 105 | &keys[i as usize], 106 | &mut RNG::new(RngAlgorithm::OsRng), 107 | ) 108 | .unwrap(), 109 | ); 110 | let valid = 111 | ThresholdCoin::verify_share(&shares[i as usize], name, &keys[0].get_public_key()) 112 | .unwrap(); 113 | assert!(valid); 114 | } 115 | 116 | let coin1 = ThresholdCoin::assemble(&shares[0..3].to_vec()).unwrap(); 117 | let coin2 = ThresholdCoin::assemble(&shares[1..4].to_vec()).unwrap(); 118 | assert_eq!(coin1, coin2); 119 | assert!(coin1 < 2 && coin1 >= 0); 120 | } 121 | 122 | #[test] 123 | fn test_invalid_share() { 124 | let keys = KeyGenerator::generate_keys( 125 | 3, 126 | 5, 127 | &mut RNG::new(RngAlgorithm::OsRng), 128 | &ThresholdScheme::Cks05, 129 | &Group::Bls12381, 130 | &Option::None, 131 | ) 132 | .unwrap(); 133 | let name = b"Label"; 134 | let mut shares = Vec::new(); 135 | let keys2 = KeyGenerator::generate_keys( 136 | 3, 137 | 5, 138 | &mut RNG::new(RngAlgorithm::OsRng), 139 | &ThresholdScheme::Cks05, 140 | &Group::Bls12381, 141 | &Option::None, 142 | ) 143 | .unwrap(); 144 | 145 | for i in 0..3 { 146 | shares.push( 147 | ThresholdCoin::create_share( 148 | name, 149 | &keys2[i as usize], 150 | &mut RNG::new(RngAlgorithm::OsRng), 151 | ) 152 | .unwrap(), 153 | ); 154 | let valid = 155 | ThresholdCoin::verify_share(&shares[i as usize], name, &keys[0].get_public_key()) 156 | .unwrap(); 157 | assert!(!valid); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/common.rs: -------------------------------------------------------------------------------- 1 | use mcore::{ 2 | hmac::{hkdf_expand, hkdf_extract, MC_SHA2}, 3 | rand::RAND, 4 | }; 5 | 6 | use crate::{ 7 | groups::ec::*, 8 | interface::{DecryptionShare, DlShare}, 9 | rand::RNG, 10 | scheme_types_impl::GroupDetails, 11 | }; 12 | 13 | use crate::groups::group::GroupOperations; 14 | use crate::integers::sizedint::SizedBigInt; 15 | use theta_proto::scheme_types::Group; 16 | 17 | use crate::groups::group::GroupElement; 18 | 19 | /* 20 | share secret x using shamir secret sharing with n parties and a threshold of k 21 | */ 22 | pub fn shamir_share( 23 | x: &SizedBigInt, 24 | k: usize, 25 | n: usize, 26 | rng: &mut RNG, 27 | ) -> (Vec, Vec) { 28 | let mut coeff: Vec = Vec::new(); 29 | let group = x.get_group(); 30 | let q = group.get_order(); 31 | 32 | for _ in 0..k - 1 { 33 | coeff.push(SizedBigInt::new_rand(&group, &q, rng)); 34 | } 35 | 36 | coeff.push(SizedBigInt::new_copy(x)); 37 | let mut shares: Vec = Vec::new(); 38 | let mut h: Vec = Vec::new(); 39 | 40 | for j in 1..n + 1 { 41 | let xi = horner(&SizedBigInt::new_int(&group, j as isize), &mut coeff); 42 | let mut hi = GroupElement::new(&group); 43 | hi = hi.pow(&xi); 44 | h.push(hi); 45 | 46 | shares.push(xi); 47 | } 48 | 49 | (shares, h) 50 | } 51 | 52 | /* 53 | evaluate polynomial defined by the vector of coefficients a at point x 54 | */ 55 | pub fn eval_pol(x: &SizedBigInt, a: &Vec) -> SizedBigInt { 56 | let len = (a.len()) as i32; 57 | let group = x.get_group(); 58 | let mut val = SizedBigInt::new_int(&group, 0); 59 | let q = group.get_order(); 60 | 61 | for i in 0..len - 1 { 62 | let mut tmp = SizedBigInt::new_copy(&a[i as usize].clone()); 63 | let mut xi = x.clone(); 64 | 65 | xi = xi.pow_mod(&SizedBigInt::new_int(&group, (len - i - 1) as isize), &q); 66 | tmp = tmp.mul_mod(&xi, &group.get_order()); 67 | val = val.add(&tmp).rmod(&q); 68 | } 69 | 70 | val = val.add(&a[(len - 1) as usize]).rmod(&q); 71 | 72 | val 73 | } 74 | 75 | /* 76 | faster way to evaluate polynomials, source https://en.wikipedia.org/wiki/Horner%27s_method 77 | */ 78 | pub fn horner(x: &SizedBigInt, a: &Vec) -> SizedBigInt { 79 | let mut result = a[0].clone(); // Initialize result 80 | let order = x.get_group().get_order(); 81 | for i in 1..a.len() { 82 | result = result.mul_mod(&x, &order).add(&a[i]).rmod(&order); 83 | } 84 | 85 | return result; 86 | } 87 | 88 | /* byte-wise xor between two byte vectors */ 89 | pub fn xor(v1: Vec, v2: Vec) -> Vec { 90 | let v3: Vec = v1.iter().zip(v2.iter()).map(|(&x1, &x2)| x1 ^ x2).collect(); 91 | 92 | v3 93 | } 94 | 95 | pub fn gen_symm_key(rng: &mut RNG) -> [u8; 32] { 96 | let prk: &mut [u8] = &mut [0; 32]; 97 | let mut ikm: Vec = Vec::new(); 98 | for _ in 0..32 { 99 | ikm.push(rng.getbyte()); 100 | } 101 | 102 | let salt: Vec = Vec::new(); 103 | hkdf_extract(MC_SHA2, 32, prk, Option::Some(&salt), &ikm); 104 | 105 | let k: &mut [u8; 32] = &mut [0; 32]; 106 | hkdf_expand(MC_SHA2, 32, k, 16, prk, &[0]); 107 | 108 | *k 109 | } 110 | 111 | /* 112 | perform lagrange interpolation over a vector of dl shares 113 | */ 114 | pub fn interpolate(shares: &Vec) -> GroupElement { 115 | let ids: Vec = (0..shares.len()).map(|x| shares[x].get_id()).collect(); 116 | let mut ry = GroupElement::new(&shares[0].get_group()); 117 | 118 | for i in 0..shares.len() { 119 | let l = lagrange_coeff(&shares[0].get_group(), &ids, shares[i].get_id() as i32); 120 | let mut ui = shares[i].get_data().clone(); 121 | ui = ui.pow(&l); 122 | 123 | if i == 0 { 124 | ry = ui; 125 | } else { 126 | ry = ry.mul(&ui); 127 | } 128 | } 129 | 130 | ry 131 | } 132 | 133 | pub fn lagrange_coeff(group: &Group, indices: &[u16], i: i32) -> SizedBigInt { 134 | let mut prod = SizedBigInt::new_int(group, 1); 135 | let q = group.get_order(); 136 | 137 | for k in 0..indices.len() { 138 | let j = indices[k] as i32; 139 | 140 | if i != j { 141 | let mut ij; 142 | let val = (j - i).abs(); 143 | 144 | if i > j { 145 | ij = q.clone(); 146 | ij = ij.sub(&SizedBigInt::new_int(group, val as isize)); 147 | } else { 148 | ij = SizedBigInt::new_int(group, val as isize); 149 | } 150 | ij = ij.inv_mod(&q); 151 | ij = ij.mul_mod(&SizedBigInt::new_int(group, j as isize), &q); 152 | 153 | prod = prod.rmod(&q); 154 | prod = prod.mul_mod(&ij, &q); 155 | } 156 | } 157 | 158 | prod = prod.rmod(&q); 159 | prod 160 | } 161 | -------------------------------------------------------------------------------- /src/core/protocols/src/threshold_coin/protocol.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | use std::sync::Arc; 3 | 4 | use chrono::Utc; 5 | use log::{debug, error, info, warn}; 6 | use theta_events::event::Event; 7 | use theta_network::types::message::NetMessage; 8 | use theta_schemes::interface::{CoinShare, Serializable, ThresholdCoin}; 9 | use theta_schemes::keys::keys::PrivateKeyShare; 10 | use theta_schemes::rand::RNG; 11 | use tonic::async_trait; 12 | 13 | use crate::interface::{ProtocolError, ThresholdRoundProtocol}; 14 | 15 | use super::message_types::CoinMessage; 16 | 17 | pub struct ThresholdCoinProtocol { 18 | private_key: Arc, 19 | name: Vec, 20 | valid_shares: Vec, 21 | finished: bool, 22 | coin: Option, 23 | received_share_ids: HashSet, 24 | } 25 | 26 | impl ThresholdRoundProtocol for ThresholdCoinProtocol { 27 | type ProtocolMessage = CoinMessage; 28 | 29 | fn do_round(&mut self) -> Result { 30 | // compute and send coin share 31 | let share = ThresholdCoin::create_share( 32 | &self.name, 33 | &self.private_key, 34 | &mut RNG::new(theta_schemes::rand::RngAlgorithm::OsRng), 35 | )?; 36 | 37 | self.received_share_ids.insert(share.get_id()); 38 | self.valid_shares.push(share.clone()); 39 | Ok(CoinMessage::new(share)) 40 | } 41 | 42 | fn is_ready_for_next_round(&self) -> bool { 43 | self.valid_shares.len() >= self.private_key.get_threshold() as usize 44 | } 45 | 46 | fn is_ready_to_finalize(&self) -> bool { 47 | self.valid_shares.len() >= self.private_key.get_threshold() as usize 48 | } 49 | 50 | fn finalize(&mut self) -> Result, ProtocolError> { 51 | let assemble_result = ThresholdCoin::assemble(&self.valid_shares); 52 | match assemble_result { 53 | Ok(result) => { 54 | self.coin = Some(result); 55 | self.finished = true; 56 | info!("Coin generated"); 57 | return Ok(vec![result]) 58 | }, 59 | Err(scheme_error) => { 60 | return Err(ProtocolError::SchemeError(scheme_error)) 61 | } 62 | } 63 | } 64 | 65 | fn update(&mut self, message: Self::ProtocolMessage)-> Result<(), ProtocolError> { 66 | 67 | match message { 68 | CoinMessage::ShareMessage(share) => { 69 | info!( 70 | "Received share with share_id: {:?}.", 71 | share.get_id() 72 | ); 73 | if self.finished { 74 | return Ok(()); //handle better this case 75 | } 76 | 77 | if self.received_share_ids.contains(&share.get_id()) { 78 | warn!( 79 | "Found share with id {:?} to be DUPLICATE. Share will be ignored.", 80 | share.get_id() 81 | ); 82 | return Ok(()); 83 | } 84 | self.received_share_ids.insert(share.get_id()); 85 | 86 | let verification_result = 87 | ThresholdCoin::verify_share(&share, &self.name, &self.private_key.get_public_key()); 88 | match verification_result { 89 | Ok(is_valid) => { 90 | if !is_valid { 91 | warn!( 92 | "Received INVALID share with id {:?}. Share will be ingored.", 93 | share.get_id() 94 | ); 95 | return Ok(()); 96 | } 97 | } 98 | Err(err) => { 99 | warn!("Encountered error when validating share with id {:?}. Error:{:?}. Share will be ingored.", err, share.get_id()); 100 | return Ok(()); 101 | } 102 | } 103 | 104 | self.valid_shares.push(share); 105 | 106 | debug!( 107 | "Valid shares: {:?}, needed: {:?}", 108 | self.valid_shares.len(), 109 | self.private_key.get_threshold() 110 | ); 111 | 112 | return Ok(()) 113 | }, 114 | _ => { 115 | todo!() //default case 116 | } 117 | } 118 | 119 | } 120 | } 121 | 122 | impl ThresholdCoinProtocol { 123 | pub fn new( 124 | private_key: Arc, 125 | name: &Vec, 126 | ) -> Self { 127 | ThresholdCoinProtocol { 128 | private_key, 129 | name: name.clone(), 130 | valid_shares: Vec::new(), 131 | finished: false, 132 | coin: Option::None, 133 | received_share_ids: HashSet::new(), 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/thetacrypt_blockchain_stub/readme.md: -------------------------------------------------------------------------------- 1 | # Blockchain Stub 2 | 3 | This module aims to provide the abstraction of a blockchain platform, exposing the intended interface to Thetacrypt. 4 | 5 | In its integration mode, Thetacrypt relies on two proxy modules to communicate with the blockchain: a P2PProxy and a TOBProxy. 6 | At the current stage, both behaviors are merged into the same module proxy in the network package. 7 | 8 | The important thing to know is that, when in integration mode, Thetacrypt can forward a message in the network assuming access to a start p2p network, 9 | or to a total order broadcast channel that ensures and enforces that every party (server) in the network will receive messages in the same order. 10 | 11 | Firstly, the blockchain stub implements the interface that a target platform into which Thetacrypt can be integrated needs to implement. 12 | Secondly, gives an easy way to test the integration communication and the logic of protocols that need TOB. 13 | 14 | ## How to run Theatacrypt in integration mode 15 | 16 | The following guide mirrors the steps of the main one under `/src` to run a simple network of $4$ Thetacrypt nodes, a client, plus an instance of a blockchain stub. 17 | 18 | ### Generating server configuration 19 | 20 | The steps to generate the configuration files are the following, assuming `../src` as cwd, and that one wants a local deployment. 21 | 22 | 1. Create two files with the IP addresses of the servers, and of the proxies. For example you can use: 23 | 24 | ``` 25 | cat > conf/server_ips.txt << EOF 26 | 127.0.0.1 27 | 127.0.0.1 28 | 127.0.0.1 29 | 127.0.0.1 30 | EOF 31 | ``` 32 | 33 | and 34 | 35 | ``` 36 | cat > conf/proxy_ips.txt << EOF 37 | 127.0.0.1 38 | 127.0.0.1 39 | 127.0.0.1 40 | 127.0.0.1 41 | EOF 42 | ``` 43 | 44 | Here the proxy IPs are all localhost (or all the same) because we are using the stub, otherwise, here we will have a list of the IPs of different blockchain nodes, to which every thetacrypt instance needs to connect. 45 | 46 | 2. Generate configuration files: 47 | 48 | ``` 49 | cargo run --bin confgen -- --ip-file conf/server_ips.txt --port-strategy consecutive --outdir=conf -i --integration-file conf/proxy_ips.txt --proxy-port 30000 --stub 50 | ``` 51 | 52 | The option `--port-strategy` can be `static` or `consecutive`. The first uses the same port for each IP (suited for a distributed deployment), and the latter assigns incremental values of the port to the IPs (suited for a local deployment). 53 | 54 | The two options `-i` and `--integration-file` are used to generate different configuration files for the server that in this mode do not need the information about every other node in the network. 55 | 56 | The binary `confgen` generates an extra config file, `client.json`, that has a list of the servers' public information: ID, IP, and rpc_port. This information can be used by a client script to call Thetacrypt's services on each node. 57 | 58 | The option `--stub` will create an extra config file `stub.json`, that has a list of the servers' p2p information. 59 | 60 | 61 | 3. Generate the keys for each server. 62 | 63 | This step is the same as in the local deployment. 64 | 65 | 66 | ### Starting the server binary 67 | 68 | The server is implemented in `bin` and can be started using `src\bin\proxy_server.rs`. 69 | From the root directory of the `src` project start 4 terminals and run, respectively: 70 | ``` 71 | cargo run --bin server -- --config-file conf/server_1.json --key-file conf/node1.keystore 72 | cargo run --bin server -- --config-file conf/server_2.json --key-file conf/node2.keystore 73 | cargo run --bin server -- --config-file conf/server_3.json --key-file conf/node3.keystore 74 | cargo run --bin server -- --config-file conf/server_4.json --key-file conf/node4.keystore 75 | ``` 76 | 77 | The server prints info messages, to see them set the following environment variable: `RUST_LOG=info` 78 | (or see here for more possibilities: https://docs.rs/env_logger/latest/env_logger/). 79 | 80 | You should see each server process print that it is connected to the others and ready to receive client requests. 81 | 82 | **The server can also be run without specifying the `--key-file` flag, this is optional.** In the future, the service will support algorithms to generate the key(DKG) or compute randomness in a distributed manner without any previous setup. 83 | 84 | ## Run an example client 85 | 86 | An RPC client, meant only to be used as an example, can be found in `\src\bin\client.rs`. To run this client, open a new terminal and run: 87 | ``` 88 | cargo run --bin client -- --config-file=conf/client.json 89 | ``` 90 | The client presents a menu of options for experimenting with the different schemes provided by the service. For example, in the case of a decryption operation, it creates a ciphertext and then submits a decryption request to each server using the `decrypt()` RPC endpoints. 91 | The code waits for the key **Enter** to be pressed before submitting each request. 92 | 93 | ## Run an example stub 94 | 95 | To run the blockchain stub, 96 | 97 | ``` 98 | cd thetacrypt_blockchain_stub 99 | ``` 100 | 101 | and run: 102 | 103 | ``` 104 | RUST_LOG=info cargo run --bin server -- --config-file ../conf/stub.json 105 | ``` -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa2048/rsa.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | use crate::rsa2048::big; 21 | use crate::rsa2048::ff; 22 | use crate::rsa2048::ff::SF; 23 | use crate::rsa2048::ff::DF; 24 | 25 | use crate::rand::RAND; 26 | 27 | pub const RFS: usize = (big::MODBYTES as usize) * ff::FFLEN; 28 | pub const SHA256: usize = 32; 29 | pub const SHA384: usize = 48; 30 | pub const SHA512: usize = 64; 31 | 32 | pub const SL: usize = ff::SL; 33 | pub const DL: usize = ff::DL; 34 | 35 | pub const HASH_TYPE: usize = SHA256; 36 | 37 | pub struct RsaPrivateKey { 38 | p: SF, 39 | q: SF, 40 | dp: SF, 41 | dq: SF, 42 | c: SF, 43 | } 44 | 45 | pub struct RsaPublicKey { 46 | e: isize, 47 | n: DF, 48 | } 49 | 50 | pub fn new_private_key() -> RsaPrivateKey { 51 | RsaPrivateKey { 52 | p: SF::new(), 53 | q: SF::new(), 54 | dp: SF::new(), 55 | dq: SF::new(), 56 | c: SF::new(), 57 | } 58 | } 59 | 60 | pub fn new_public_key() -> RsaPublicKey { 61 | RsaPublicKey { 62 | e: 0, 63 | n: DF::new(), 64 | } 65 | } 66 | 67 | pub fn set_public_key(pk: &mut RsaPublicKey,e: isize, f: &[u8]) { 68 | pk.e=e; 69 | let mut r = DF::new(); 70 | r.frombytes(f); 71 | pk.n.copy(&r); 72 | } 73 | 74 | // Input private key from OpenSSL format 75 | // e.g as in openssl rsa -in privkey.pem -noout -text 76 | // Note order swap - For MIRACL c=1/p mod q, for OpenSSL c=1/q mod p 77 | pub fn rsa_private_key_from_openssl(p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey) { 78 | prv.p.frombytes(q); 79 | prv.q.frombytes(p); 80 | prv.dp.frombytes(dq); 81 | prv.dq.frombytes(dp); 82 | prv.c.frombytes(c); 83 | } 84 | 85 | pub fn key_pair_from_openssl(e: isize, p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 86 | rsa_private_key_from_openssl(p,q,dp,dq,c,prv); 87 | pbc.n = prv.p.mul(&prv.q); 88 | pbc.e = e; 89 | } 90 | 91 | pub fn key_pair(rng: &mut impl RAND, e: isize, prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 92 | /* IEEE1363 A16.11/A16.12 more or less */ 93 | let mut t = SF::new(); 94 | let mut p1 = SF::new(); 95 | let mut q1 = SF::new(); 96 | 97 | loop { 98 | prv.p.random(rng); 99 | while prv.p.lastbits(2) != 3 { 100 | prv.p.inc(1) 101 | } 102 | while !prv.p.isprime(rng) { 103 | prv.p.inc(4); 104 | } 105 | 106 | p1.copy(&prv.p); 107 | p1.dec(1); 108 | 109 | if p1.cfactor(e) { 110 | continue; 111 | } 112 | break; 113 | } 114 | 115 | loop { 116 | prv.q.random(rng); 117 | while prv.q.lastbits(2) != 3 { 118 | prv.q.inc(1) 119 | } 120 | while !prv.q.isprime(rng) { 121 | prv.q.inc(4); 122 | } 123 | 124 | q1.copy(&prv.q); 125 | q1.dec(1); 126 | 127 | if q1.cfactor(e) { 128 | continue; 129 | } 130 | 131 | break; 132 | } 133 | 134 | pbc.n = prv.p.mul(&prv.q); 135 | pbc.e = e; 136 | 137 | // Note this only works for the 3 mod 4 primes generated as above. 138 | 139 | t.copy(&p1); 140 | t.shr(); 141 | prv.dp.set(e); 142 | prv.dp.invmodp(&t); 143 | if prv.dp.parity() == 0 { 144 | prv.dp.add(&t) 145 | } 146 | prv.dp.norm(); 147 | 148 | t.copy(&q1); 149 | t.shr(); 150 | prv.dq.set(e); 151 | prv.dq.invmodp(&t); 152 | if prv.dq.parity() == 0 { 153 | prv.dq.add(&t) 154 | } 155 | prv.dq.norm(); 156 | 157 | prv.c.copy(&prv.p); 158 | prv.c.invmodp(&prv.q); 159 | } 160 | 161 | 162 | /* destroy the Private Key structure */ 163 | pub fn private_key_kill(prv: &mut RsaPrivateKey) { 164 | prv.p.zero(); 165 | prv.q.zero(); 166 | prv.dp.zero(); 167 | prv.dq.zero(); 168 | prv.c.zero(); 169 | } 170 | 171 | /* RSA encryption with the public key */ 172 | pub fn encrypt(pbc: &RsaPublicKey, f: &[u8], g: &mut [u8]) { 173 | let mut r = DF::new(); 174 | r.frombytes(f); 175 | r.power(pbc.e, &pbc.n); 176 | r.tobytes(g); 177 | } 178 | 179 | /* RSA decryption with the private key */ 180 | pub fn decrypt(prv: &RsaPrivateKey, g: &[u8], f: &mut [u8]) { 181 | let mut r = DF::new(); 182 | 183 | r.frombytes(g); 184 | let mut jp = r.dmod(&prv.p); 185 | let mut jq = r.dmod(&prv.q); 186 | 187 | jp.skpow(&prv.dp, &prv.p); 188 | jq.skpow(&prv.dq, &prv.q); 189 | 190 | r.zero(); 191 | r.dscopy(&jp); 192 | jp.rmod(&prv.q); 193 | if jp.comp(&jq) > 0 { 194 | jq.add(&prv.q) 195 | } 196 | jq.sub(&jp); 197 | jq.norm(); 198 | 199 | let mut t = prv.c.mul(&jq); 200 | jq = t.dmod(&prv.q); 201 | 202 | t = jq.mul(&prv.p); 203 | r.add(&t); 204 | r.norm(); 205 | 206 | r.tobytes(f); 207 | } 208 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa3072/rsa.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | use crate::rsa3072::big; 21 | use crate::rsa3072::ff; 22 | use crate::rsa3072::ff::SF; 23 | use crate::rsa3072::ff::DF; 24 | 25 | use crate::rand::RAND; 26 | 27 | pub const RFS: usize = (big::MODBYTES as usize) * ff::FFLEN; 28 | pub const SHA256: usize = 32; 29 | pub const SHA384: usize = 48; 30 | pub const SHA512: usize = 64; 31 | 32 | pub const SL: usize = ff::SL; 33 | pub const DL: usize = ff::DL; 34 | 35 | pub const HASH_TYPE: usize = SHA256; 36 | 37 | pub struct RsaPrivateKey { 38 | p: SF, 39 | q: SF, 40 | dp: SF, 41 | dq: SF, 42 | c: SF, 43 | } 44 | 45 | pub struct RsaPublicKey { 46 | e: isize, 47 | n: DF, 48 | } 49 | 50 | pub fn new_private_key() -> RsaPrivateKey { 51 | RsaPrivateKey { 52 | p: SF::new(), 53 | q: SF::new(), 54 | dp: SF::new(), 55 | dq: SF::new(), 56 | c: SF::new(), 57 | } 58 | } 59 | 60 | pub fn new_public_key() -> RsaPublicKey { 61 | RsaPublicKey { 62 | e: 0, 63 | n: DF::new(), 64 | } 65 | } 66 | 67 | pub fn set_public_key(pk: &mut RsaPublicKey,e: isize, f: &[u8]) { 68 | pk.e=e; 69 | let mut r = DF::new(); 70 | r.frombytes(f); 71 | pk.n.copy(&r); 72 | } 73 | 74 | // Input private key from OpenSSL format 75 | // e.g as in openssl rsa -in privkey.pem -noout -text 76 | // Note order swap - For MIRACL c=1/p mod q, for OpenSSL c=1/q mod p 77 | pub fn rsa_private_key_from_openssl(p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey) { 78 | prv.p.frombytes(q); 79 | prv.q.frombytes(p); 80 | prv.dp.frombytes(dq); 81 | prv.dq.frombytes(dp); 82 | prv.c.frombytes(c); 83 | } 84 | 85 | pub fn key_pair_from_openssl(e: isize, p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 86 | rsa_private_key_from_openssl(p,q,dp,dq,c,prv); 87 | pbc.n = prv.p.mul(&prv.q); 88 | pbc.e = e; 89 | } 90 | 91 | pub fn key_pair(rng: &mut impl RAND, e: isize, prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 92 | /* IEEE1363 A16.11/A16.12 more or less */ 93 | let mut t = SF::new(); 94 | let mut p1 = SF::new(); 95 | let mut q1 = SF::new(); 96 | 97 | loop { 98 | prv.p.random(rng); 99 | while prv.p.lastbits(2) != 3 { 100 | prv.p.inc(1) 101 | } 102 | while !prv.p.isprime(rng) { 103 | prv.p.inc(4); 104 | } 105 | 106 | p1.copy(&prv.p); 107 | p1.dec(1); 108 | 109 | if p1.cfactor(e) { 110 | continue; 111 | } 112 | break; 113 | } 114 | 115 | loop { 116 | prv.q.random(rng); 117 | while prv.q.lastbits(2) != 3 { 118 | prv.q.inc(1) 119 | } 120 | while !prv.q.isprime(rng) { 121 | prv.q.inc(4); 122 | } 123 | 124 | q1.copy(&prv.q); 125 | q1.dec(1); 126 | 127 | if q1.cfactor(e) { 128 | continue; 129 | } 130 | 131 | break; 132 | } 133 | 134 | pbc.n = prv.p.mul(&prv.q); 135 | pbc.e = e; 136 | 137 | // Note this only works for the 3 mod 4 primes generated as above. 138 | 139 | t.copy(&p1); 140 | t.shr(); 141 | prv.dp.set(e); 142 | prv.dp.invmodp(&t); 143 | if prv.dp.parity() == 0 { 144 | prv.dp.add(&t) 145 | } 146 | prv.dp.norm(); 147 | 148 | t.copy(&q1); 149 | t.shr(); 150 | prv.dq.set(e); 151 | prv.dq.invmodp(&t); 152 | if prv.dq.parity() == 0 { 153 | prv.dq.add(&t) 154 | } 155 | prv.dq.norm(); 156 | 157 | prv.c.copy(&prv.p); 158 | prv.c.invmodp(&prv.q); 159 | } 160 | 161 | 162 | /* destroy the Private Key structure */ 163 | pub fn private_key_kill(prv: &mut RsaPrivateKey) { 164 | prv.p.zero(); 165 | prv.q.zero(); 166 | prv.dp.zero(); 167 | prv.dq.zero(); 168 | prv.c.zero(); 169 | } 170 | 171 | /* RSA encryption with the public key */ 172 | pub fn encrypt(pbc: &RsaPublicKey, f: &[u8], g: &mut [u8]) { 173 | let mut r = DF::new(); 174 | r.frombytes(f); 175 | r.power(pbc.e, &pbc.n); 176 | r.tobytes(g); 177 | } 178 | 179 | /* RSA decryption with the private key */ 180 | pub fn decrypt(prv: &RsaPrivateKey, g: &[u8], f: &mut [u8]) { 181 | let mut r = DF::new(); 182 | 183 | r.frombytes(g); 184 | let mut jp = r.dmod(&prv.p); 185 | let mut jq = r.dmod(&prv.q); 186 | 187 | jp.skpow(&prv.dp, &prv.p); 188 | jq.skpow(&prv.dq, &prv.q); 189 | 190 | r.zero(); 191 | r.dscopy(&jp); 192 | jp.rmod(&prv.q); 193 | if jp.comp(&jq) > 0 { 194 | jq.add(&prv.q) 195 | } 196 | jq.sub(&jp); 197 | jq.norm(); 198 | 199 | let mut t = prv.c.mul(&jq); 200 | jq = t.dmod(&prv.q); 201 | 202 | t = jq.mul(&prv.p); 203 | r.add(&t); 204 | r.norm(); 205 | 206 | r.tobytes(f); 207 | } 208 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rsa4096/rsa.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | use crate::rsa4096::big; 21 | use crate::rsa4096::ff; 22 | use crate::rsa4096::ff::SF; 23 | use crate::rsa4096::ff::DF; 24 | 25 | use crate::rand::RAND; 26 | 27 | pub const RFS: usize = (big::MODBYTES as usize) * ff::FFLEN; 28 | pub const SHA256: usize = 32; 29 | pub const SHA384: usize = 48; 30 | pub const SHA512: usize = 64; 31 | 32 | pub const SL: usize = ff::SL; 33 | pub const DL: usize = ff::DL; 34 | 35 | pub const HASH_TYPE: usize = SHA256; 36 | 37 | pub struct RsaPrivateKey { 38 | p: SF, 39 | q: SF, 40 | dp: SF, 41 | dq: SF, 42 | c: SF, 43 | } 44 | 45 | pub struct RsaPublicKey { 46 | e: isize, 47 | n: DF, 48 | } 49 | 50 | pub fn new_private_key() -> RsaPrivateKey { 51 | RsaPrivateKey { 52 | p: SF::new(), 53 | q: SF::new(), 54 | dp: SF::new(), 55 | dq: SF::new(), 56 | c: SF::new(), 57 | } 58 | } 59 | 60 | pub fn new_public_key() -> RsaPublicKey { 61 | RsaPublicKey { 62 | e: 0, 63 | n: DF::new(), 64 | } 65 | } 66 | 67 | pub fn set_public_key(pk: &mut RsaPublicKey,e: isize, f: &[u8]) { 68 | pk.e=e; 69 | let mut r = DF::new(); 70 | r.frombytes(f); 71 | pk.n.copy(&r); 72 | } 73 | 74 | // Input private key from OpenSSL format 75 | // e.g as in openssl rsa -in privkey.pem -noout -text 76 | // Note order swap - For MIRACL c=1/p mod q, for OpenSSL c=1/q mod p 77 | pub fn rsa_private_key_from_openssl(p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey) { 78 | prv.p.frombytes(q); 79 | prv.q.frombytes(p); 80 | prv.dp.frombytes(dq); 81 | prv.dq.frombytes(dp); 82 | prv.c.frombytes(c); 83 | } 84 | 85 | pub fn key_pair_from_openssl(e: isize, p: &[u8],q: &[u8],dp: &[u8],dq: &[u8],c: &[u8], prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 86 | rsa_private_key_from_openssl(p,q,dp,dq,c,prv); 87 | pbc.n = prv.p.mul(&prv.q); 88 | pbc.e = e; 89 | } 90 | 91 | pub fn key_pair(rng: &mut impl RAND, e: isize, prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) { 92 | /* IEEE1363 A16.11/A16.12 more or less */ 93 | let mut t = SF::new(); 94 | let mut p1 = SF::new(); 95 | let mut q1 = SF::new(); 96 | 97 | loop { 98 | prv.p.random(rng); 99 | while prv.p.lastbits(2) != 3 { 100 | prv.p.inc(1) 101 | } 102 | while !prv.p.isprime(rng) { 103 | prv.p.inc(4); 104 | } 105 | 106 | p1.copy(&prv.p); 107 | p1.dec(1); 108 | 109 | if p1.cfactor(e) { 110 | continue; 111 | } 112 | break; 113 | } 114 | 115 | loop { 116 | prv.q.random(rng); 117 | while prv.q.lastbits(2) != 3 { 118 | prv.q.inc(1) 119 | } 120 | while !prv.q.isprime(rng) { 121 | prv.q.inc(4); 122 | } 123 | 124 | q1.copy(&prv.q); 125 | q1.dec(1); 126 | 127 | if q1.cfactor(e) { 128 | continue; 129 | } 130 | 131 | break; 132 | } 133 | 134 | pbc.n = prv.p.mul(&prv.q); 135 | pbc.e = e; 136 | 137 | // Note this only works for the 3 mod 4 primes generated as above. 138 | 139 | t.copy(&p1); 140 | t.shr(); 141 | prv.dp.set(e); 142 | prv.dp.invmodp(&t); 143 | if prv.dp.parity() == 0 { 144 | prv.dp.add(&t) 145 | } 146 | prv.dp.norm(); 147 | 148 | t.copy(&q1); 149 | t.shr(); 150 | prv.dq.set(e); 151 | prv.dq.invmodp(&t); 152 | if prv.dq.parity() == 0 { 153 | prv.dq.add(&t) 154 | } 155 | prv.dq.norm(); 156 | 157 | prv.c.copy(&prv.p); 158 | prv.c.invmodp(&prv.q); 159 | } 160 | 161 | 162 | /* destroy the Private Key structure */ 163 | pub fn private_key_kill(prv: &mut RsaPrivateKey) { 164 | prv.p.zero(); 165 | prv.q.zero(); 166 | prv.dp.zero(); 167 | prv.dq.zero(); 168 | prv.c.zero(); 169 | } 170 | 171 | /* RSA encryption with the public key */ 172 | pub fn encrypt(pbc: &RsaPublicKey, f: &[u8], g: &mut [u8]) { 173 | let mut r = DF::new(); 174 | r.frombytes(f); 175 | r.power(pbc.e, &pbc.n); 176 | r.tobytes(g); 177 | } 178 | 179 | /* RSA decryption with the private key */ 180 | pub fn decrypt(prv: &RsaPrivateKey, g: &[u8], f: &mut [u8]) { 181 | let mut r = DF::new(); 182 | 183 | r.frombytes(g); 184 | let mut jp = r.dmod(&prv.p); 185 | let mut jq = r.dmod(&prv.q); 186 | 187 | jp.skpow(&prv.dp, &prv.p); 188 | jq.skpow(&prv.dq, &prv.q); 189 | 190 | r.zero(); 191 | r.dscopy(&jp); 192 | jp.rmod(&prv.q); 193 | if jp.comp(&jq) > 0 { 194 | jq.add(&prv.q) 195 | } 196 | jq.sub(&jp); 197 | jq.norm(); 198 | 199 | let mut t = prv.c.mul(&jq); 200 | jq = t.dmod(&prv.q); 201 | 202 | t = jq.mul(&prv.p); 203 | r.add(&t); 204 | r.norm(); 205 | 206 | r.tobytes(f); 207 | } 208 | -------------------------------------------------------------------------------- /src/core/schemes/src/dl_schemes/signatures/frost_tests.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use crate::dl_schemes::signatures::frost::{commit, deserialize_scalar, FrostOptions}; 3 | use crate::interface::{ThresholdSignature, ThresholdSignatureOptions}; 4 | use crate::keys::key_generator::KeyGenerator; 5 | use crate::rand::StaticRNG; 6 | use crate::{ 7 | groups::group::GroupElement, 8 | integers::sizedint::SizedBigInt, 9 | interface::{Serializable, Signature, ThresholdScheme}, 10 | keys::keys::PrivateKeyShare, 11 | rand::{RngAlgorithm, RNG}, 12 | }; 13 | use hex::FromHex; 14 | use theta_proto::scheme_types::Group; 15 | 16 | use super::frost::{FrostPrivateKey, FrostPublicKey, PublicCommitment}; 17 | 18 | /* ToDo: make test vector work 19 | 20 | Test vectors can be found at https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-15.html#name-frosted25519-sha-512-2 21 | 22 | #[test] 23 | #[allow(dead_code)] 24 | fn test_vector() { 25 | let group = Group::Ed25519; 26 | /* let x = SizedBigInt::from_hex( 27 | &group, 28 | "7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304", 29 | );*/ 30 | let x = deserialize_scalar( 31 | &group, 32 | &hex::decode("7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304").unwrap(), 33 | ); 34 | let y = GroupElement::new_pow_big(&group, &x); 35 | 36 | println!("y: {}", hex::encode(y.to_bytes())); 37 | 38 | let msg = Vec::from_hex("74657374").expect("invalid hex"); 39 | let _coeff = SizedBigInt::from_hex( 40 | &group, 41 | "178199860edd8c62f5212ee91eff1295d0d670ab4ed4506866bae57e7030b204", 42 | ); 43 | 44 | let k = 2; 45 | let n = 3; 46 | 47 | let share1 = deserialize_scalar( 48 | &group, 49 | &hex::decode("929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509").unwrap(), 50 | ); 51 | let share2 = SizedBigInt::from_hex( 52 | &group, 53 | "a91e66e012e4364ac9aaa405fcafd370402d9859f7b6685c07eed76bf409e80d", 54 | ); 55 | let share3 = SizedBigInt::from_hex( 56 | &group, 57 | "d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02", 58 | ); 59 | 60 | let mut s_serialize = share1.to_bytes(); 61 | s_serialize.reverse(); 62 | let t = s_serialize.len() - 1; 63 | s_serialize[t] &= 0x1f; 64 | println!("share: {}", hex::encode(s_serialize)); 65 | 66 | let c1 = GroupElement::new_pow_big(&group, &share1); 67 | let c2 = GroupElement::new_pow_big(&group, &share2); 68 | let c3 = GroupElement::new_pow_big(&group, &share3); 69 | 70 | let h = vec![c1, c2, c3]; 71 | 72 | let pk = FrostPublicKey::new(n, k, &group, &y, &h); 73 | let sk1 = FrostPrivateKey::new(1, &share1, &pk); 74 | let sk2 = FrostPrivateKey::new(2, &share2, &pk); 75 | let sk3 = FrostPrivateKey::new(3, &share3, &pk); 76 | 77 | let mut rng1 = RNG::Static(StaticRNG::new( 78 | "069cd85f631d5f7f2721ed5e40519b1366f340a87c2f6856363dbdcda348a7501fd2e39e111cdc266f6c0f4d0fd45c947761f1f5d3cb583dfcb9bbaf8d4c9fec".to_string(), true)); 79 | 80 | let (comm1, nonce1) = commit(&sk1, &mut rng1); 81 | 82 | let hiding_nonce_1 = deserialize_scalar( 83 | &group, 84 | &hex::decode("812d6104142944d5a55924de6d49940956206909f2acaeedecda2b726e630407").unwrap(), 85 | ); 86 | let hiding_nonce_3 = SizedBigInt::from_hex( 87 | &group, 88 | "c256de65476204095ebdc01bd11dc10e57b36bc96284595b8215222374f99c0e", 89 | ); 90 | 91 | let binding_nonce_1 = SizedBigInt::from_hex( 92 | &group, 93 | "b1110165fc2334149750b28dd813a39244f315cff14d4e89e6142f262ed83301", 94 | ); 95 | let binding_nonce_3 = SizedBigInt::from_hex( 96 | &group, 97 | "243d71944d929063bc51205714ae3c2218bd3451d0214dfb5aeec2a90c35180d", 98 | ); 99 | 100 | // TODO: Fix failing test here 101 | assert_eq!(hiding_nonce_1, nonce1.hiding_nonce); 102 | 103 | /* 104 | 105 | let comm1 = PublicCommitment::new( 106 | 1, 107 | GroupElement::new_pow_big(&group, &hiding_nonce_1), 108 | GroupElement::new_pow_big(&group, &binding_nonce_1), 109 | ); 110 | 111 | let comm3 = PublicCommitment::new( 112 | 3, 113 | GroupElement::new_pow_big(&group, &hiding_nonce_3), 114 | GroupElement::new_pow_big(&group, &binding_nonce_3), 115 | ); 116 | 117 | let _ = i1.do_round().unwrap(); 118 | let _ = i3.do_round().unwrap(); 119 | 120 | i1.set_commitment(&comm1); 121 | i3.set_commitment(&comm3); 122 | 123 | let r1 = super::frost::FrostRoundResult::RoundOne(comm1); 124 | let r3 = super::frost::FrostRoundResult::RoundOne(comm3); 125 | 126 | i1.update(&r1).expect("error updating rr with r1"); 127 | i1.update(&r3).expect("error updating rr with r3"); 128 | i3.update(&r1).expect("error updating rr with r1"); 129 | i3.update(&r3).expect("error updating rr with r3"); 130 | 131 | assert!(i1.is_ready_for_next_round()); 132 | assert!(i3.is_ready_for_next_round()); 133 | 134 | let r1 = i1.do_round().unwrap(); 135 | let r3 = i3.do_round().unwrap(); 136 | let e1 = BigImpl::from_hex( 137 | &group, 138 | "001719ab5a53ee1a12095cd088fd149702c0720ce5fd2f29dbecf24b7281b603", 139 | ); 140 | let e3 = BigImpl::from_hex( 141 | &group, 142 | "bd86125de990acc5e1f13781d8e32c03a9bbd4c53539bbc106058bfd14326007", 143 | );*/ 144 | 145 | /*if let FrostRoundResult::RoundTwo(r) = r1 { 146 | println!("{}", hex::encode(r.get_share().to_bytes())); 147 | assert!(e1.equals(&r.get_share())); 148 | } 149 | 150 | if let FrostRoundResult::RoundTwo(r) = r3 { 151 | assert!(e3.equals(&r.get_share())); 152 | }*/ 153 | }*/ 154 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/bn254/bls.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | use crate::bn254::big; 20 | use crate::bn254::big::BIG; 21 | use crate::bn254::fp::FP; 22 | use crate::bn254::ecp; 23 | use crate::bn254::ecp::ECP; 24 | use crate::bn254::dbig::DBIG; 25 | use crate::bn254::ecp2::ECP2; 26 | //use crate::bn254::fp4::FP4; 27 | use crate::bn254::pair; 28 | use crate::bn254::rom; 29 | use crate::hmac; 30 | 31 | /* Boneh-Lynn-Shacham signature 128-bit API Functions */ 32 | 33 | /* Loosely (for now) following https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-02 */ 34 | 35 | // Minimal-signature-size variant 36 | 37 | pub const BFS: usize = big::MODBYTES as usize; 38 | pub const BGS: usize = big::MODBYTES as usize; 39 | pub const BLS_OK: isize = 0; 40 | pub const BLS_FAIL: isize = -1; 41 | 42 | // NOTE this must be accessed in unsafe mode. 43 | // But it is just written to once at start-up, so actually safe. 44 | 45 | // Best not to use precomp if stack memory limited - i.e. embedded use 46 | // Uncomment to use precomp 47 | // static mut G2_TAB: [FP4; ecp::G2_TABLE] = [FP4::new(); ecp::G2_TABLE]; 48 | 49 | fn ceil(a: usize,b: usize) -> usize { 50 | (a-1)/b+1 51 | } 52 | 53 | /* output u \in F_p */ 54 | fn hash_to_field(hash: usize,hlen: usize ,u: &mut [FP], dst: &[u8],m: &[u8],ctr: usize) { 55 | let q = BIG::new_ints(&rom::MODULUS); 56 | let el = ceil(q.nbits()+ecp::AESKEY*8,8); 57 | 58 | let mut okm: [u8;256]=[0;256]; 59 | let mut fd: [u8;128]=[0;128]; 60 | 61 | hmac::xmd_expand(hash,hlen,&mut okm,el*ctr,&dst,&m); 62 | for i in 0..ctr { 63 | for j in 0..el { 64 | fd[j]=okm[el*i+j]; 65 | } 66 | u[i]=FP::new_big(&DBIG::frombytes(&fd[0 .. el]).dmod(&q)); 67 | } 68 | } 69 | 70 | /* hash a message to an ECP point, using SHA2, random oracle method */ 71 | #[allow(non_snake_case)] 72 | pub fn bls_hash_to_point(m: &[u8]) -> ECP { 73 | let dst= "BLS_SIG_BN254G1_XMD:SHA-256_SVDW_RO_NUL_"; 74 | 75 | let mut u: [FP; 2] = [ 76 | FP::new(), 77 | FP::new(), 78 | ]; 79 | hash_to_field(hmac::MC_SHA2,ecp::HASH_TYPE,&mut u,dst.as_bytes(),m,2); 80 | 81 | let mut P=ECP::map2point(&u[0]); 82 | let P1=ECP::map2point(&u[1]); 83 | 84 | P.add(&P1); 85 | P.cfp(); 86 | P.affine(); 87 | P 88 | } 89 | 90 | pub fn init() -> isize { 91 | // Uncomment to use precomp 92 | // let g = ECP2::generator(); 93 | // if g.is_infinity() { 94 | // return BLS_FAIL; 95 | // } 96 | // unsafe { 97 | // pair::precomp(&mut G2_TAB, &g); 98 | // } 99 | BLS_OK 100 | } 101 | 102 | /* generate key pair, private key s, public key w */ 103 | pub fn key_pair_generate(ikm: &[u8], s: &mut [u8], w: &mut [u8]) -> isize { 104 | let r = BIG::new_ints(&rom::CURVE_ORDER); 105 | let el = ceil(3*ceil(r.nbits(),8),2); 106 | let g = ECP2::generator(); 107 | let mut len: [u8; 2] = [0; 2]; 108 | hmac::inttobytes(el,&mut len); 109 | 110 | let salt="BLS-SIG-KEYGEN-SALT-"; 111 | 112 | let mut prk: [u8;64]=[0;64]; 113 | let mut okm: [u8;128]=[0;128]; 114 | let mut aikm: [u8;65]=[0;65]; 115 | let likm=ikm.len(); 116 | for i in 0..likm { 117 | aikm[i]=ikm[i]; 118 | } 119 | aikm[likm]=0; 120 | 121 | let hlen=ecp::HASH_TYPE; 122 | 123 | hmac::hkdf_extract(hmac::MC_SHA2,hlen,&mut prk,Some(&salt.as_bytes()),&aikm[0 .. likm+1]); 124 | hmac::hkdf_expand(hmac::MC_SHA2,hlen,&mut okm,el,&prk[0 .. hlen],&len); 125 | 126 | let mut dx = DBIG::frombytes(&okm[0 .. el]); 127 | let sc = dx.dmod(&r); 128 | sc.tobytes(s); 129 | // SkToPk 130 | pair::g2mul(&g, &sc).tobytes(w,true); // true for public key compression 131 | BLS_OK 132 | } 133 | 134 | /* Sign message m using private key s to produce signature sig */ 135 | 136 | pub fn core_sign(sig: &mut [u8], m: &[u8], s: &[u8]) -> isize { 137 | let d = bls_hash_to_point(m); 138 | let sc = BIG::frombytes(&s); 139 | pair::g1mul(&d, &sc).tobytes(sig, true); 140 | BLS_OK 141 | } 142 | 143 | /* Verify signature given message m, the signature sig, and the public key w */ 144 | 145 | pub fn core_verify(sig: &[u8], m: &[u8], w: &[u8]) -> isize { 146 | let hm = bls_hash_to_point(m); 147 | let mut d = ECP::frombytes(&sig); 148 | 149 | if !pair::g1member(&d) { 150 | return BLS_FAIL; 151 | } 152 | d.neg(); 153 | 154 | let pk = ECP2::frombytes(&w); 155 | if !pair::g2member(&pk) { 156 | return BLS_FAIL; 157 | } 158 | 159 | // Uncomment to use precomp 160 | // Use new multi-pairing mechanism 161 | //let mut r = pair::initmp(); 162 | // pair::another(&mut r,&g,&d); 163 | 164 | //unsafe { 165 | // pair::another_pc(&mut r, &G2_TAB, &d); 166 | //} 167 | //pair::another(&mut r, &pk, &hm); 168 | //let mut v = pair::miller(&mut r); 169 | 170 | //.. or else do not use precomp! 171 | let g = ECP2::generator(); 172 | let mut v = pair::ate2(&g, &d, &pk, &hm); 173 | 174 | v = pair::fexp(&v); 175 | if v.isunity() { 176 | return BLS_OK; 177 | } 178 | BLS_FAIL 179 | } 180 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/bls12381/bls.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | use crate::bls12381::big; 20 | use crate::bls12381::big::BIG; 21 | use crate::bls12381::fp::FP; 22 | use crate::bls12381::ecp; 23 | use crate::bls12381::ecp::ECP; 24 | use crate::bls12381::dbig::DBIG; 25 | use crate::bls12381::ecp2::ECP2; 26 | //use crate::bls12381::fp4::FP4; 27 | use crate::bls12381::pair; 28 | use crate::bls12381::rom; 29 | use crate::hmac; 30 | 31 | /* Boneh-Lynn-Shacham signature 128-bit API Functions */ 32 | 33 | /* Loosely (for now) following https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-02 */ 34 | 35 | // Minimal-signature-size variant 36 | 37 | pub const BFS: usize = big::MODBYTES as usize; 38 | pub const BGS: usize = big::MODBYTES as usize; 39 | pub const BLS_OK: isize = 0; 40 | pub const BLS_FAIL: isize = -1; 41 | 42 | // NOTE this must be accessed in unsafe mode. 43 | // But it is just written to once at start-up, so actually safe. 44 | 45 | // Best not to use precomp if stack memory limited - i.e. embedded use 46 | // Uncomment to use precomp 47 | // static mut G2_TAB: [FP4; ecp::G2_TABLE] = [FP4::new(); ecp::G2_TABLE]; 48 | 49 | fn ceil(a: usize,b: usize) -> usize { 50 | (a-1)/b+1 51 | } 52 | 53 | /* output u \in F_p */ 54 | fn hash_to_field(hash: usize,hlen: usize ,u: &mut [FP], dst: &[u8],m: &[u8],ctr: usize) { 55 | let q = BIG::new_ints(&rom::MODULUS); 56 | let el = ceil(q.nbits()+ecp::AESKEY*8,8); 57 | 58 | let mut okm: [u8;256]=[0;256]; 59 | let mut fd: [u8;128]=[0;128]; 60 | 61 | hmac::xmd_expand(hash,hlen,&mut okm,el*ctr,&dst,&m); 62 | for i in 0..ctr { 63 | for j in 0..el { 64 | fd[j]=okm[el*i+j]; 65 | } 66 | u[i]=FP::new_big(&DBIG::frombytes(&fd[0 .. el]).dmod(&q)); 67 | } 68 | } 69 | 70 | /* hash a message to an ECP point, using SHA2, random oracle method */ 71 | #[allow(non_snake_case)] 72 | pub fn bls_hash_to_point(m: &[u8]) -> ECP { 73 | let dst= "BLS_SIG_BLS12381G1_XMD:SHA-256_SVDW_RO_NUL_"; 74 | 75 | let mut u: [FP; 2] = [ 76 | FP::new(), 77 | FP::new(), 78 | ]; 79 | hash_to_field(hmac::MC_SHA2,ecp::HASH_TYPE,&mut u,dst.as_bytes(),m,2); 80 | 81 | let mut P=ECP::map2point(&u[0]); 82 | let P1=ECP::map2point(&u[1]); 83 | 84 | P.add(&P1); 85 | P.cfp(); 86 | P.affine(); 87 | P 88 | } 89 | 90 | pub fn init() -> isize { 91 | // Uncomment to use precomp 92 | // let g = ECP2::generator(); 93 | // if g.is_infinity() { 94 | // return BLS_FAIL; 95 | // } 96 | // unsafe { 97 | // pair::precomp(&mut G2_TAB, &g); 98 | // } 99 | BLS_OK 100 | } 101 | 102 | /* generate key pair, private key s, public key w */ 103 | pub fn key_pair_generate(ikm: &[u8], s: &mut [u8], w: &mut [u8]) -> isize { 104 | let r = BIG::new_ints(&rom::CURVE_ORDER); 105 | let el = ceil(3*ceil(r.nbits(),8),2); 106 | let g = ECP2::generator(); 107 | let mut len: [u8; 2] = [0; 2]; 108 | hmac::inttobytes(el,&mut len); 109 | 110 | let salt="BLS-SIG-KEYGEN-SALT-"; 111 | 112 | let mut prk: [u8;64]=[0;64]; 113 | let mut okm: [u8;128]=[0;128]; 114 | let mut aikm: [u8;65]=[0;65]; 115 | let likm=ikm.len(); 116 | for i in 0..likm { 117 | aikm[i]=ikm[i]; 118 | } 119 | aikm[likm]=0; 120 | 121 | let hlen=ecp::HASH_TYPE; 122 | 123 | hmac::hkdf_extract(hmac::MC_SHA2,hlen,&mut prk,Some(&salt.as_bytes()),&aikm[0 .. likm+1]); 124 | hmac::hkdf_expand(hmac::MC_SHA2,hlen,&mut okm,el,&prk[0 .. hlen],&len); 125 | 126 | let mut dx = DBIG::frombytes(&okm[0 .. el]); 127 | let sc = dx.dmod(&r); 128 | sc.tobytes(s); 129 | // SkToPk 130 | pair::g2mul(&g, &sc).tobytes(w,true); // true for public key compression 131 | BLS_OK 132 | } 133 | 134 | /* Sign message m using private key s to produce signature sig */ 135 | 136 | pub fn core_sign(sig: &mut [u8], m: &[u8], s: &[u8]) -> isize { 137 | let d = bls_hash_to_point(m); 138 | let sc = BIG::frombytes(&s); 139 | pair::g1mul(&d, &sc).tobytes(sig, true); 140 | BLS_OK 141 | } 142 | 143 | /* Verify signature given message m, the signature sig, and the public key w */ 144 | 145 | pub fn core_verify(sig: &[u8], m: &[u8], w: &[u8]) -> isize { 146 | let hm = bls_hash_to_point(m); 147 | let mut d = ECP::frombytes(&sig); 148 | 149 | if !pair::g1member(&d) { 150 | return BLS_FAIL; 151 | } 152 | d.neg(); 153 | 154 | let pk = ECP2::frombytes(&w); 155 | if !pair::g2member(&pk) { 156 | return BLS_FAIL; 157 | } 158 | 159 | // Uncomment to use precomp 160 | // Use new multi-pairing mechanism 161 | //let mut r = pair::initmp(); 162 | // pair::another(&mut r,&g,&d); 163 | 164 | //unsafe { 165 | // pair::another_pc(&mut r, &G2_TAB, &d); 166 | //} 167 | //pair::another(&mut r, &pk, &hm); 168 | //let mut v = pair::miller(&mut r); 169 | 170 | //.. or else do not use precomp! 171 | let g = ECP2::generator(); 172 | let mut v = pair::ate2(&g, &d, &pk, &hm); 173 | 174 | v = pair::fexp(&v); 175 | if v.isunity() { 176 | return BLS_OK; 177 | } 178 | BLS_FAIL 179 | } 180 | -------------------------------------------------------------------------------- /src/core/schemes/mcore/src/rand.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 MIRACL UK Ltd. 3 | * 4 | * This file is part of MIRACL Core 5 | * (see https://github.com/miracl/core). 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | //mod hash256; 21 | 22 | use crate::hash256::HASH256; 23 | 24 | const RAND_NK: usize = 21; 25 | const RAND_NJ: usize = 6; 26 | const RAND_NV: usize = 8; 27 | 28 | pub trait RAND { 29 | /* Initialize RNG with some real entropy from some external source */ 30 | fn seed(&mut self, rawlen: usize, raw: &[u8]); 31 | /* get random byte */ 32 | fn getbyte(&mut self) -> u8; 33 | } 34 | 35 | // Marsaglia-Zaman random generator (https://projecteuclid.org/euclid.aoap/1177005878) 36 | // Analysis: https://ieeexplore.ieee.org/document/669305 37 | #[allow(non_camel_case_types)] 38 | pub struct RAND_impl { 39 | ira: [u32; RAND_NK], /* random number... */ 40 | rndptr: usize, 41 | borrow: u32, 42 | pool_ptr: usize, 43 | pool: [u8; 32], 44 | } 45 | 46 | impl RAND_impl { 47 | pub fn new() -> RAND_impl { 48 | RAND_impl { 49 | ira: [0; RAND_NK], 50 | rndptr: 0, 51 | borrow: 0, 52 | pool_ptr: 0, 53 | pool: [0; 32], 54 | } 55 | } 56 | 57 | #[allow(dead_code)] 58 | pub fn clean(&mut self) { 59 | self.pool_ptr = 0; 60 | self.rndptr = 0; 61 | for i in 0..32 { 62 | self.pool[i] = 0 63 | } 64 | for i in 0..RAND_NK { 65 | self.ira[i] = 0 66 | } 67 | self.borrow = 0; 68 | } 69 | 70 | fn sbrand(&mut self) -> u32 { 71 | /* Marsaglia & Zaman random number generator */ 72 | self.rndptr += 1; 73 | if self.rndptr < RAND_NK { 74 | return self.ira[self.rndptr]; 75 | } 76 | self.rndptr = 0; 77 | let mut k = RAND_NK - RAND_NJ; 78 | for i in 0..RAND_NK { 79 | /* calculate next NK values */ 80 | if k == RAND_NK { 81 | k = 0 82 | } 83 | let t = self.ira[k]; 84 | let pdiff = t.wrapping_sub(self.ira[i]).wrapping_sub(self.borrow); 85 | if pdiff < t { 86 | self.borrow = 0 87 | } 88 | if pdiff > t { 89 | self.borrow = 1 90 | } 91 | self.ira[i] = pdiff; 92 | k += 1; 93 | } 94 | self.ira[0] 95 | } 96 | 97 | fn sirand(&mut self, seed: u32) { 98 | let mut m: u32 = 1; 99 | let mut sd = seed; 100 | self.borrow = 0; 101 | self.rndptr = 0; 102 | self.ira[0] ^= sd; 103 | for i in 1..RAND_NK { 104 | /* fill initialisation vector */ 105 | let inn = (RAND_NV * i) % RAND_NK; 106 | self.ira[inn] ^= m; /* note XOR */ 107 | let t = m; 108 | m = sd.wrapping_sub(m); 109 | sd = t; 110 | } 111 | for _ in 0..10000 { 112 | self.sbrand(); 113 | } /* "warm-up" & stir the generator */ 114 | } 115 | 116 | fn fill_pool(&mut self) { 117 | let mut sh = HASH256::new(); 118 | for _ in 0..128 { 119 | sh.process((self.sbrand() & 0xff) as u8) 120 | } 121 | let w = sh.hash(); 122 | for i in 0..32 { 123 | self.pool[i] = w[i] 124 | } 125 | self.pool_ptr = 0; 126 | } 127 | 128 | fn pack(b: [u8; 4]) -> u32 { 129 | /* pack 4 bytes into a 32-bit Word */ 130 | (((b[3] as u32) & 0xff) << 24) 131 | | (((b[2] as u32) & 0xff) << 16) 132 | | (((b[1] as u32) & 0xff) << 8) 133 | | ((b[0] as u32) & 0xff) 134 | } 135 | } 136 | 137 | impl RAND for RAND_impl { 138 | fn seed(&mut self, rawlen: usize, raw: &[u8]) { 139 | /* initialise from at least 128 byte string of raw random entropy */ 140 | let mut b: [u8; 4] = [0; 4]; 141 | let mut sh = HASH256::new(); 142 | self.pool_ptr = 0; 143 | 144 | for i in 0..RAND_NK { 145 | self.ira[i] = 0 146 | } 147 | if rawlen > 0 { 148 | for i in 0..rawlen { 149 | sh.process(raw[i]); 150 | } 151 | let digest = sh.hash(); 152 | 153 | /* initialise PRNG from distilled randomness */ 154 | 155 | for i in 0..8 { 156 | b[0] = digest[4 * i]; 157 | b[1] = digest[4 * i + 1]; 158 | b[2] = digest[4 * i + 2]; 159 | b[3] = digest[4 * i + 3]; 160 | self.sirand(RAND_impl::pack(b)); 161 | } 162 | } 163 | self.fill_pool(); 164 | } 165 | 166 | fn getbyte(&mut self) -> u8 { 167 | let r = self.pool[self.pool_ptr]; 168 | self.pool_ptr += 1; 169 | if self.pool_ptr >= 32 { 170 | self.fill_pool() 171 | } 172 | r 173 | } 174 | } 175 | 176 | /* test main program */ 177 | /* 178 | fn main() { 179 | let mut raw : [u8;100]=[0;100]; 180 | let mut rng=RAND_impl::new(); 181 | 182 | rng.clean(); 183 | for i in 0..100 {raw[i]=i as u8} 184 | 185 | rng.seed(100,&raw); 186 | 187 | for _ in 0..1000 { 188 | print!("{:03} ",rng.getbyte()); 189 | } 190 | } 191 | */ 192 | --------------------------------------------------------------------------------