From f1cc42f4f5e646be9ebfea46428a20fe28abb4cc Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Tue, 8 Oct 2024 14:30:57 +0200 Subject: [PATCH 01/11] feat: make `create` and `prepare_execute` not return payload --- lib/src/bin/murmur/main.rs | 73 ++++++++++------ lib/src/lib.rs | 173 ++++++++++++++++--------------------- 2 files changed, 120 insertions(+), 126 deletions(-) diff --git a/lib/src/bin/murmur/main.rs b/lib/src/bin/murmur/main.rs index a945986..b04e5a1 100644 --- a/lib/src/bin/murmur/main.rs +++ b/lib/src/bin/murmur/main.rs @@ -15,9 +15,7 @@ */ use clap::{Parser, Subcommand}; use murmur_lib::{ - create, - etf::{self, runtime_types::node_template_runtime::RuntimeCall::Balances}, - idn_connect, prepare_execute, BlockNumber, MurmurStore, + create, etf, idn_connect, prepare_execute, BlockNumber, BoundedVec, MurmurStore, RuntimeCall, }; use sp_core::crypto::Ss58Codec; use std::fs::File; @@ -95,6 +93,7 @@ async fn main() -> Result<(), Box> { match &cli.commands { Commands::New(args) => { println!("🏭 Murmur: Generating Merkle mountain range"); + // 1. prepare block schedule let mut schedule: Vec = Vec::new(); for i in 2..args.validity + 2 { @@ -102,57 +101,77 @@ async fn main() -> Result<(), Box> { let next_block_number: BlockNumber = current_block_number + i; schedule.push(next_block_number); } + // 2. create mmr - let (call, mmr_store) = create( - args.name.as_bytes().to_vec(), + let create_data = create( args.seed.as_bytes().to_vec(), ephem_msk, schedule, round_pubkey_bytes, ) .map_err(|_| CLIError::MurmurCreationFailed)?; + // 3. add to storage - write_mmr_store(mmr_store.clone(), MMR_STORE_FILEPATH); - // sign and send the call - let from = dev::alice(); - let _events = client + write_mmr_store(create_data.mmr_store.clone(), MMR_STORE_FILEPATH); + + // 4. build the call + let call = etf::tx().murmur().create( + create_data.root, + create_data.size, + BoundedVec(args.name.as_bytes().to_vec()), + ); + + // 5. sign and send the call + client .tx() - .sign_and_submit_then_watch_default(&call, &from) + .sign_and_submit_then_watch_default(&call, &dev::alice()) .await?; + println!("✅ MMR proxy account creation successful!"); } Commands::Execute(args) => { - // build balance transfer + // 1. build proxied call let from_ss58 = sp_core::crypto::AccountId32::from_ss58check(&args.to) .map_err(|_| CLIError::InvalidRecipient)?; - let bytes: &[u8] = from_ss58.as_ref(); let from_ss58_sized: [u8; 32] = bytes.try_into().map_err(|_| CLIError::InvalidRecipient)?; let to = subxt::utils::AccountId32::from(from_ss58_sized); + let balance_transfer_call = + RuntimeCall::Balances(etf::balances::Call::transfer_allow_death { + dest: subxt::utils::MultiAddress::<_, u32>::from(to), + value: args.amount, + }); - let balance_transfer_call = Balances(etf::balances::Call::transfer_allow_death { - dest: subxt::utils::MultiAddress::<_, u32>::from(to), - value: args.amount, - }); - + // 2. load the MMR store let store: MurmurStore = load_mmr_store(MMR_STORE_FILEPATH)?; - let target_block_number: BlockNumber = current_block_number + 1; - println!("💾 Recovered Murmur store from local file"); - let tx = prepare_execute( - args.name.as_bytes().to_vec(), + + // 3. get the proxy data + let proxy_data = prepare_execute( + // args.name.as_bytes().to_vec(), args.seed.as_bytes().to_vec(), - target_block_number, + current_block_number + 1, store, - balance_transfer_call, + &balance_transfer_call, ) .map_err(|_| CLIError::MurmurExecutionFailed)?; - // submit the tx using alice to sign it - let _result = client + + // 4. build the call + let call = etf::tx().murmur().proxy( + BoundedVec(args.name.as_bytes().to_vec()), + proxy_data.position, + proxy_data.hash, + proxy_data.ciphertext, + proxy_data.proof_items, + proxy_data.size, + balance_transfer_call, + ); + // 5. sign and send the call + client .tx() - .sign_and_submit_then_watch_default(&tx, &dev::alice()) - .await; + .sign_and_submit_then_watch_default(&call, &dev::alice()) + .await?; } } println!("Elapsed time: {:.2?}", before.elapsed()); diff --git a/lib/src/lib.rs b/lib/src/lib.rs index fbed771..db23d73 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use etf::runtime_types::bounded_collections::bounded_vec::BoundedVec; +use beefy::{known_payloads, Commitment, Payload}; use murmur_core::types::{Identity, IdentityBuilder}; use subxt::{ backend::rpc::RpcClient, client::OnlineClient, config::SubstrateConfig, ext::codec::Encode, @@ -22,16 +22,14 @@ use subxt::{ use w3f_bls::{DoublePublicKey, SerializableToBytes, TinyBLS377}; use zeroize::Zeroize; -pub use beefy::{known_payloads, Commitment, Payload}; -pub use etf::{ - murmur::calls::types::{Create, Proxy}, - runtime_types::node_template_runtime::RuntimeCall, +pub use etf::runtime_types::{ + bounded_collections::bounded_vec::BoundedVec, + node_template_runtime::RuntimeCall, }; pub use murmur_core::{ murmur::{Error, MurmurStore}, types::BlockNumber, }; -pub use subxt::tx::Payload as TxPayload; // Generate an interface that we can use from the node's metadata. #[subxt::subxt(runtime_metadata_path = "artifacts/metadata.scale")] @@ -51,22 +49,39 @@ impl IdentityBuilder for BasicIdBuilder { Identity::new(&commitment.encode()) } } -/// create a new MMR and use it to generate a valid call to create a murmur wallet -/// returns the call data and the mmr_store + +/// Data needed to build a valid call for creating a murmur wallet. +pub struct CreateData { + /// The root of the MMR + pub root: Vec, + /// The size of the MMR + pub size: u64, + pub mmr_store: MurmurStore, +} + +/// Data needed to build a valid call for a proxied execution. +pub struct ProxyData { + pub position: u64, + /// The hash of the commitment + pub hash: Vec, + pub ciphertext: Vec, + pub proof_items: Vec>, + pub size: u64, +} + +/// Create a new MMR and return the data needed to build a valid call for creating a murmur wallet. /// -/// * `name`: The name of the murmur proxy /// * `seed`: The seed used to generate otp codes /// * `ephem_msk`: An ephemeral secret key TODO: replace with an hkdf? /// * `block_schedule`: A list of block numbers when the wallet will be executable /// * `round_pubkey_bytes`: The Ideal Network randomness beacon public key /// pub fn create( - name: Vec, mut seed: Vec, mut ephem_msk: [u8; 32], block_schedule: Vec, round_pubkey_bytes: Vec, -) -> Result<(TxPayload, MurmurStore), Error> { +) -> Result { let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes) .map_err(|_| Error::InvalidPubkey)?; let mmr_store = MurmurStore::new::( @@ -79,35 +94,33 @@ pub fn create( seed.zeroize(); let root = mmr_store.root.clone(); - let call = etf::tx() - .murmur() - .create(root.0, mmr_store.metadata.len() as u64, BoundedVec(name)); - Ok((call, mmr_store)) + Ok(CreateData { + root: root.0, + size: mmr_store.metadata.len() as u64, + mmr_store, + }) } -/// prepare the call for immediate execution -/// Note to self: in the future, we can consider ways to prune the murmurstore as OTP codes are consumed -/// for example, we can take the next values from the map, reducing storage to 0 over time -/// However, to do this we need to think of a way to prove it with a merkle proof -/// my thought is that we would have a subtree, so first we prove that the subtree is indeed in the parent MMR -/// then we prove that the specific leaf is in the subtree. -/// We could potentially use that idea as a way to optimize the execute function in general. Rather than -/// loading the entire MMR into memory, we really only need to load a minimal subtree containing the leaf we want to consume -/// -> add this to the 'future work' section later -/// -/// * `name`: The name of the murmur proxy +/// Return the data needed for the immediate execution of the proxied call. /// * `seed`: The seed used to generate otp codes /// * `when`: The block number when OTP codeds should be generated /// * `store`: A murmur store -/// * `call`: Any valid runtime call +/// * `call`: Proxied call. Any valid runtime call /// +// Note to self: in the future, we can consider ways to prune the murmurstore as OTP codes are consumed +// for example, we can take the next values from the map, reducing storage to 0 over time +// However, to do this we need to think of a way to prove it with a merkle proof +// my thought is that we would have a subtree, so first we prove that the subtree is indeed in the parent MMR +// then we prove that the specific leaf is in the subtree. +// We could potentially use that idea as a way to optimize the execute function in general. Rather than +// loading the entire MMR into memory, we really only need to load a minimal subtree containing the leaf we want to consume +// -> add this to the 'future work' section later pub fn prepare_execute( - name: Vec, mut seed: Vec, when: BlockNumber, store: MurmurStore, - call: RuntimeCall, -) -> Result, Error> { + call: &RuntimeCall, +) -> Result { let (proof, commitment, ciphertext, pos) = store.execute(seed.clone(), when, call.encode())?; seed.zeroize(); let size = proof.mmr_size(); @@ -117,15 +130,13 @@ pub fn prepare_execute( .map(|leaf| leaf.0.clone()) .collect::>(); - Ok(etf::tx().murmur().proxy( - BoundedVec(name), - pos, - commitment, + Ok(ProxyData { + position: pos, + hash: commitment, ciphertext, proof_items, size, - call, - )) + }) } /// Async connection to the Ideal Network @@ -167,87 +178,63 @@ pub async fn idn_connect( #[cfg(test)] mod tests { - use super::*; - use subxt::tx::TxPayload; #[test] - pub fn it_can_create_an_mmr_store_and_call_data() { - let name = b"name".to_vec(); + pub fn it_can_create_an_mmr_store() { let seed = b"seed".to_vec(); let ephem_msk = [1; 32]; let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); - let (call, mmr_store) = create( - name.clone(), - seed, + let create_data = create( + seed.clone(), ephem_msk, - block_schedule, - double_public_bytes, + block_schedule.clone(), + double_public_bytes.clone(), ) .unwrap(); - let expected_call = etf::tx().murmur().create( - mmr_store.root.0, - mmr_store.metadata.len() as u64, - BoundedVec(name), - ); - - let actual_details = call.validation_details().unwrap(); - let expected_details = expected_call.validation_details().unwrap(); - - assert_eq!(actual_details.pallet_name, expected_details.pallet_name,); - - assert_eq!(actual_details.call_name, expected_details.call_name,); + let mmr_store = MurmurStore::new::( + seed, + block_schedule, + ephem_msk, + DoublePublicKey::::from_bytes(&double_public_bytes).unwrap(), + ) + .unwrap(); - assert_eq!(actual_details.hash, expected_details.hash,); + assert_eq!(create_data.mmr_store.root, mmr_store.root); + assert_eq!(create_data.size, 7); } #[test] pub fn it_can_prepare_valid_execution_call_data() { - let name = b"name".to_vec(); let seed = b"seed".to_vec(); let ephem_msk = [1; 32]; let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); - let (_call, mmr_store) = create( - name.clone(), - seed.clone(), - ephem_msk, - block_schedule, - double_public_bytes, - ) - .unwrap(); + let create_data = + create(seed.clone(), ephem_msk, block_schedule, double_public_bytes).unwrap(); let bob = subxt_signer::sr25519::dev::bob().public_key(); - let bob2 = subxt_signer::sr25519::dev::bob().public_key(); let balance_transfer_call = - etf::runtime_types::node_template_runtime::RuntimeCall::Balances( + &etf::runtime_types::node_template_runtime::RuntimeCall::Balances( etf::balances::Call::transfer_allow_death { dest: subxt::utils::MultiAddress::<_, u32>::from(bob), value: 1, }, ); - let balance_transfer_call_2 = - etf::runtime_types::node_template_runtime::RuntimeCall::Balances( - etf::balances::Call::transfer_allow_death { - dest: subxt::utils::MultiAddress::<_, u32>::from(bob2), - value: 1, - }, - ); - - let actual_call = prepare_execute( - name.clone(), + let proxy_data = prepare_execute( seed.clone(), 1, - mmr_store.clone(), + create_data.mmr_store.clone(), balance_transfer_call, ) .unwrap(); - let (proof, commitment, ciphertext, _pos) = mmr_store - .execute(seed.clone(), 1, balance_transfer_call_2.encode()) + let (proof, commitment, ciphertext, _pos) = create_data + .mmr_store + .execute(seed.clone(), 1, balance_transfer_call.encode()) .unwrap(); let size = proof.mmr_size(); @@ -256,23 +243,11 @@ mod tests { .iter() .map(|leaf| leaf.0.clone()) .collect::>(); - let expected_call = etf::tx().murmur().proxy( - BoundedVec(name), - 0, - commitment, - ciphertext, - proof_items, - size, - balance_transfer_call_2, - ); - - let actual_details = actual_call.validation_details().unwrap(); - let expected_details = expected_call.validation_details().unwrap(); - - assert_eq!(actual_details.pallet_name, expected_details.pallet_name,); - - assert_eq!(actual_details.call_name, expected_details.call_name,); - assert_eq!(actual_details.hash, expected_details.hash,); + assert_eq!(proxy_data.position, 0); + assert_eq!(proxy_data.hash, commitment); + assert_eq!(proxy_data.ciphertext, ciphertext); + assert_eq!(proxy_data.proof_items, proof_items); + assert_eq!(proxy_data.size, size); } } From cb96ae6328794e3bbd918b7a85a4893e520349c9 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 9 Oct 2024 12:03:51 +0200 Subject: [PATCH 02/11] feat: make data serializable --- lib/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index db23d73..f51935e 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -16,6 +16,7 @@ use beefy::{known_payloads, Commitment, Payload}; use murmur_core::types::{Identity, IdentityBuilder}; +use serde::Serialize; use subxt::{ backend::rpc::RpcClient, client::OnlineClient, config::SubstrateConfig, ext::codec::Encode, }; @@ -23,8 +24,7 @@ use w3f_bls::{DoublePublicKey, SerializableToBytes, TinyBLS377}; use zeroize::Zeroize; pub use etf::runtime_types::{ - bounded_collections::bounded_vec::BoundedVec, - node_template_runtime::RuntimeCall, + bounded_collections::bounded_vec::BoundedVec, node_template_runtime::RuntimeCall, }; pub use murmur_core::{ murmur::{Error, MurmurStore}, @@ -50,6 +50,7 @@ impl IdentityBuilder for BasicIdBuilder { } } +#[derive(Serialize)] /// Data needed to build a valid call for creating a murmur wallet. pub struct CreateData { /// The root of the MMR @@ -59,6 +60,7 @@ pub struct CreateData { pub mmr_store: MurmurStore, } +#[derive(Serialize)] /// Data needed to build a valid call for a proxied execution. pub struct ProxyData { pub position: u64, From e773af8b12e7e72536f0d5cb57f733be30e74edb Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 9 Oct 2024 14:20:20 +0200 Subject: [PATCH 03/11] feat: make mumurstore encodable and decodable --- core/src/murmur.rs | 18 +++++++++--------- core/src/types.rs | 13 +++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/core/src/murmur.rs b/core/src/murmur.rs index 4ce4018..fb2e43c 100644 --- a/core/src/murmur.rs +++ b/core/src/murmur.rs @@ -21,9 +21,9 @@ use alloc::{collections::BTreeMap, vec, vec::Vec}; #[cfg(feature = "client")] use crate::otp::BOTPGenerator; -use rand_chacha::ChaCha20Rng; use ark_std::rand::SeedableRng; use ark_std::rand::{CryptoRng, Rng}; +use rand_chacha::ChaCha20Rng; #[cfg(feature = "client")] use zeroize::Zeroize; @@ -37,6 +37,7 @@ use ckb_merkle_mountain_range::{ util::{MemMMR, MemStore}, MerkleProof, }; +use codec::{Decode, Encode}; use etf_crypto_primitives::{encryption::tlock::*, ibe::fullident::Identity}; use sha3::Digest; use w3f_bls::{DoublePublicKey, EngineBLS}; @@ -55,7 +56,7 @@ pub enum Error { TlockFailed, /// The buffer does not have enough space allocated InvalidBufferSize, - /// The seed was invalid + /// The seed was invalid InvalidSeed, /// The public key was invalid (could not be decoded) InvalidPubkey, @@ -63,7 +64,7 @@ pub enum Error { /// The murmur store contains minimal data required to use a murmur wallet #[cfg(feature = "client")] -#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Encode, Decode)] pub struct MurmurStore { /// A map of block numbers to leaf positions in the mmr pub metadata: BTreeMap, @@ -194,8 +195,8 @@ pub fn timelock_encrypt( message: &[u8], rng: R, ) -> Result, Error> { - let ciphertext = tle::(pk, ephemeral_msk, message, identity, rng) - .map_err(|_| Error::TlockFailed)?; + let ciphertext = + tle::(pk, ephemeral_msk, message, identity, rng).map_err(|_| Error::TlockFailed)?; let mut ct_bytes = Vec::new(); ciphertext .serialize_compressed(&mut ct_bytes) @@ -210,8 +211,7 @@ fn build_generator(mut seed: Vec) -> Result { hasher.update(&seed); seed.zeroize(); let hash = hasher.finalize(); - BOTPGenerator::new(hash.to_vec()) - .map_err(|_| Error::InvalidSeed) + BOTPGenerator::new(hash.to_vec()).map_err(|_| Error::InvalidSeed) } // verify the correctness of execution parameters @@ -249,10 +249,10 @@ pub fn get_key_index(b: &BTreeMap, key: &K) - mod tests { use super::*; - use w3f_bls::{DoublePublicKeyScheme, TinyBLS377}; + use ark_std::rand::SeedableRng; use rand_chacha::ChaCha20Rng; use rand_core::OsRng; - use ark_std::rand::SeedableRng; + use w3f_bls::{DoublePublicKeyScheme, TinyBLS377}; pub struct DummyIdBuilder; impl IdentityBuilder for DummyIdBuilder { diff --git a/core/src/types.rs b/core/src/types.rs index 567c487..d9b2c63 100644 --- a/core/src/types.rs +++ b/core/src/types.rs @@ -14,10 +14,12 @@ * limitations under the License. */ +use alloc::vec::Vec; use ckb_merkle_mountain_range::{Merge, Result as MMRResult}; -pub use etf_crypto_primitives::ibe::fullident::Identity; +use codec::{Decode, Encode}; use sha3::Digest; -use alloc::vec::Vec; + +pub use etf_crypto_primitives::ibe::fullident::Identity; /// The type to represent a block number pub type BlockNumber = u32; @@ -28,8 +30,7 @@ pub type Ciphertext = Vec; /// A leaf in the MMR /// The payload is an opaque, any-length vec #[derive( - Eq, PartialEq, Clone, Debug, Default, - serde::Serialize, serde::Deserialize + Eq, PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize, Encode, Decode, )] pub struct Leaf(pub Vec); impl From> for Leaf { @@ -47,7 +48,7 @@ pub struct MergeLeaves; impl Merge for MergeLeaves { type Item = Leaf; fn merge(lhs: &Self::Item, rhs: &Self::Item) -> MMRResult { - let mut hasher = sha3::Sha3_256::default(); + let mut hasher = sha3::Sha3_256::default(); hasher.update(&lhs.0); hasher.update(&rhs.0); let hash = hasher.finalize(); @@ -58,4 +59,4 @@ impl Merge for MergeLeaves { /// Something that builds unique identities (e.g. using crypto hash function) for any block number pub trait IdentityBuilder { fn build_identity(at: BlockNumber) -> Identity; -} \ No newline at end of file +} From f00241d6984641625a6aba7a48e2b07df4abefae Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 9 Oct 2024 16:04:20 +0200 Subject: [PATCH 04/11] chore: clean up comment --- lib/src/bin/murmur/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/bin/murmur/main.rs b/lib/src/bin/murmur/main.rs index b04e5a1..8f83c3c 100644 --- a/lib/src/bin/murmur/main.rs +++ b/lib/src/bin/murmur/main.rs @@ -149,7 +149,6 @@ async fn main() -> Result<(), Box> { // 3. get the proxy data let proxy_data = prepare_execute( - // args.name.as_bytes().to_vec(), args.seed.as_bytes().to_vec(), current_block_number + 1, store, From 14f571ecf1af00840133ae0a76c07a740c12cee9 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Fri, 11 Oct 2024 17:24:37 +0200 Subject: [PATCH 05/11] feat: derive ephem_msk in the lib --- Cargo.lock | 11 +++++++++++ core/Cargo.toml | 1 + core/src/murmur.rs | 26 +++++++++++++++++++++----- lib/Cargo.toml | 3 ++- lib/src/bin/murmur/main.rs | 2 -- lib/src/lib.rs | 18 ++++++++++++------ 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecbf658..45b82de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,6 +1997,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.8.1" @@ -2509,6 +2518,7 @@ dependencies = [ "ark-std", "ckb-merkle-mountain-range", "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk/?branch=dev)", + "hkdf", "parity-scale-codec", "rand_chacha", "rand_core", @@ -2529,6 +2539,7 @@ dependencies = [ "ark-std", "ckb-merkle-mountain-range", "clap", + "hkdf", "murmur-core", "murmur-test-utils", "parity-scale-codec", diff --git a/core/Cargo.toml b/core/Cargo.toml index 727bb22..cee6b81 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -27,6 +27,7 @@ rand_chacha = { version = "0.3.1" } [dev-dependencies] rand_core = { version = "0.6.4", features = ["getrandom"], default-features = false } +hkdf = "0.12.4" [features] default = ["client"] diff --git a/core/src/murmur.rs b/core/src/murmur.rs index fb2e43c..4117da9 100644 --- a/core/src/murmur.rs +++ b/core/src/murmur.rs @@ -60,6 +60,7 @@ pub enum Error { InvalidSeed, /// The public key was invalid (could not be decoded) InvalidPubkey, + KeyDerivationFailed, } /// The murmur store contains minimal data required to use a murmur wallet @@ -271,10 +272,13 @@ mod tests { keypair.public.0, ); - let ephem_msk = [1; 32]; let seed = vec![1, 2, 3]; let schedule = vec![1, 2, 3]; + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let murmur_store = MurmurStore::new::( seed.clone(), schedule.clone(), @@ -295,7 +299,6 @@ mod tests { keypair.public.0, ); - let ephem_msk = [1; 32]; let seed = vec![1, 2, 3]; let schedule = vec![ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, @@ -303,6 +306,10 @@ mod tests { let aux_data = vec![2, 3, 4, 5]; + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let murmur_store = MurmurStore::new::( seed.clone(), schedule.clone(), @@ -349,12 +356,15 @@ mod tests { keypair.public.0, ); - let ephem_msk = [1; 32]; let seed = vec![1, 2, 3]; let schedule = vec![1, 2, 3, 4, 5]; let aux_data = vec![2, 3, 4, 5]; + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let murmur_store = MurmurStore::new::( seed.clone(), schedule.clone(), @@ -381,12 +391,15 @@ mod tests { keypair.public.0, ); - let ephem_msk = [1; 32]; let seed = vec![1, 2, 3]; let schedule = vec![1, 2, 3]; let aux_data = vec![2, 3, 4, 5]; + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let murmur_store = MurmurStore::new::( seed.clone(), schedule.clone(), @@ -432,13 +445,16 @@ mod tests { keypair.public.0, ); - let ephem_msk = [1; 32]; let seed = vec![1, 2, 3]; let schedule = vec![1, 2, 3]; let other_schedule = vec![1, 2, 3, 4, 5]; let aux_data = vec![2, 3, 4, 5]; + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let murmur_store = MurmurStore::new::( seed.clone(), schedule.clone(), diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 86873e9..b0df26f 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -37,7 +37,8 @@ ark-serialize = "0.4.0" w3f-bls = "0.1.3" murmur-core = { path = "../core/", features = ["client"] } zeroize = "1.8.1" +hkdf = "0.12.4" [dev-dependencies] -murmur-test-utils = { path = "../test-utils/" } \ No newline at end of file +murmur-test-utils = { path = "../test-utils/" } diff --git a/lib/src/bin/murmur/main.rs b/lib/src/bin/murmur/main.rs index 8f83c3c..59f99fa 100644 --- a/lib/src/bin/murmur/main.rs +++ b/lib/src/bin/murmur/main.rs @@ -86,7 +86,6 @@ pub const MMR_STORE_FILEPATH: &str = "mmr_store"; async fn main() -> Result<(), Box> { let cli = Cli::parse(); let before = Instant::now(); - let ephem_msk = [1; 32]; let (client, current_block_number, round_pubkey_bytes) = idn_connect().await?; @@ -105,7 +104,6 @@ async fn main() -> Result<(), Box> { // 2. create mmr let create_data = create( args.seed.as_bytes().to_vec(), - ephem_msk, schedule, round_pubkey_bytes, ) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f51935e..9d26338 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -15,6 +15,7 @@ */ use beefy::{known_payloads, Commitment, Payload}; +use hkdf::Hkdf; use murmur_core::types::{Identity, IdentityBuilder}; use serde::Serialize; use subxt::{ @@ -74,16 +75,20 @@ pub struct ProxyData { /// Create a new MMR and return the data needed to build a valid call for creating a murmur wallet. /// /// * `seed`: The seed used to generate otp codes -/// * `ephem_msk`: An ephemeral secret key TODO: replace with an hkdf? /// * `block_schedule`: A list of block numbers when the wallet will be executable /// * `round_pubkey_bytes`: The Ideal Network randomness beacon public key /// pub fn create( mut seed: Vec, - mut ephem_msk: [u8; 32], block_schedule: Vec, round_pubkey_bytes: Vec, ) -> Result { + // Derive ephem_msk from seed using HKDF + let hk = Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk) + .map_err(|_| Error::KeyDerivationFailed)?; + let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes) .map_err(|_| Error::InvalidPubkey)?; let mmr_store = MurmurStore::new::( @@ -185,17 +190,19 @@ mod tests { #[test] pub fn it_can_create_an_mmr_store() { let seed = b"seed".to_vec(); - let ephem_msk = [1; 32]; let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); let create_data = create( seed.clone(), - ephem_msk, block_schedule.clone(), double_public_bytes.clone(), ) .unwrap(); + let hk = Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + let mmr_store = MurmurStore::new::( seed, block_schedule, @@ -211,11 +218,10 @@ mod tests { #[test] pub fn it_can_prepare_valid_execution_call_data() { let seed = b"seed".to_vec(); - let ephem_msk = [1; 32]; let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); let create_data = - create(seed.clone(), ephem_msk, block_schedule, double_public_bytes).unwrap(); + create(seed.clone(), block_schedule, double_public_bytes).unwrap(); let bob = subxt_signer::sr25519::dev::bob().public_key(); let balance_transfer_call = From 8dde14910c1f5dcad82469a710372d1664f16e93 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Mon, 14 Oct 2024 09:57:29 +0200 Subject: [PATCH 06/11] chore: add docs to murmur errors --- core/src/murmur.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/murmur.rs b/core/src/murmur.rs index 4117da9..8f32a4f 100644 --- a/core/src/murmur.rs +++ b/core/src/murmur.rs @@ -45,7 +45,9 @@ use w3f_bls::{DoublePublicKey, EngineBLS}; /// Error types for murmur wallet usage #[derive(Debug, PartialEq)] pub enum Error { + /// An error occurred when executing a call ExecuteError, + /// An error occurred when creating a murmur wallet MMRError, InconsistentStore, /// No leaf could be identified in the MMR at the specified position @@ -60,6 +62,7 @@ pub enum Error { InvalidSeed, /// The public key was invalid (could not be decoded) InvalidPubkey, + /// The key derivation failed KeyDerivationFailed, } From 8c05dfe04a6d5de4b5432975eb71a1eefc3e9897 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Mon, 14 Oct 2024 17:58:06 +0200 Subject: [PATCH 07/11] chore: improve readme check licenses and cargo files --- CHANGELOG.md | 17 ++++++++++ Cargo.toml | 3 +- README.md | 32 +++++++++++++----- core/Cargo.toml | 7 ++++ core/README.md | 33 +++++++++++++++---- core/src/lib.rs | 1 + lib/Cargo.toml | 7 ++++ lib/README.md | 67 +++++++++++++++++++++++++++++--------- lib/src/bin/murmur/main.rs | 9 ++--- test-utils/Cargo.toml | 1 + test-utils/README.md | 14 +++++++- test-utils/src/lib.rs | 1 + 12 files changed, 154 insertions(+), 38 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5237368 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 2023-10-14 + +### Added + +- Initial implementation of the Murmur API. + +[unreleased]: https://github.com/ideal-lab5/murmur/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/ideal-lab5/murmur/releases/tag/v0.1.0 diff --git a/Cargo.toml b/Cargo.toml index e17a2f7..bc4e6ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,11 @@ resolver = "2" [workspace.package] edition = "2021" -authors = ["Ideal Labs "] +authors = ["Ideal Labs "] repository = "https://github.com/ideal-lab5/murmur" homepage = "https://idealabs.network" license = "Apache-2.0" +description = "Murmur crates" [workspace.lints.rust] suspicious_double_ref_op = { level = "allow", priority = 2 } diff --git a/README.md b/README.md index 6c6bfe0..99569b4 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,39 @@ # Murmur -Murmur is an air-gapped keyless crypto wallet protocol that runs on the [Ideal Network](). This repository contains the core implementation of the murmur protocol and a CLI to allow fully non-custodial usage of murmur wallets. +Murmur is an air-gapped keyless crypto wallet protocol that runs on the [Ideal Network](https://idealabs.network). This repository contains the core implementation of the murmur protocol and a CLI to allow fully non-custodial usage of murmur wallets. -The murmur protocol enables **keyless account abstraction** capabilities for any chain bridged to the Ideal Network (alternatively, we can do this with drand). wallet is a special pure proxy that can only be executed when presented with proof that the origin knows a correct time-based OTP code. +The murmur protocol enables **keyless account abstraction** capabilities for any chain bridged to the Ideal Network (alternatively, we can do this with drand). wallet is a special pure proxy that can only be executed when presented with proof that the origin knows a correct time-based OTP code. -It is based on the [Hours of Horus](https://eprint.iacr.org/2021/715) protocol, which leverages timelock encryption and a secure OTP code generator to construct a keyless wallet scheme. Our scheme improves on this construction in several ways. +It is based on the [Hours of Horus](https://eprint.iacr.org/2021/715) protocol, which leverages timelock encryption and a secure OTP code generator to construct a keyless wallet scheme. Our scheme improves on this construction in several ways. -- We leverage the Ideal Network to instantiate practical timelock encryption, allowing the HoH scheme to be realized in the first place. -- We use a Merkle mountain range in place of a Merkle tree, allowing for arbitrary numbers of OTP codes to be generated -- JIT execution: Rather than relying on a commit-reveal scheme in order to use the wallet, our scheme uses a 'just-in-time' approach leveraging the Ideal Network's on-chain randomness, which provides the decryption key (i.e. BLS signature) necessary to verify proofs. +- **Practical Timelock Encryption**: We leverage the Ideal Network to instantiate practical timelock encryption, allowing the HoH scheme to be realized in the first place. +- **Merkle Mountain Range**: We use a Merkle mountain range in place of a Merkle tree, allowing for arbitrary numbers of OTP codes to be generated +- **Just-in-Time Execution**: Rather than relying on a commit-reveal scheme in order to use the wallet, our scheme uses a 'just-in-time' approach leveraging the Ideal Network's on-chain randomness, which provides the decryption key (i.e. BLS signature) necessary to verify proofs. ## Build -``` +To build the project, use the following command: + +```shell cargo build ``` ## Testing -``` +To run the tests, use the following command: + +```shell cargo test ``` + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the Apache-2.0. See the [LICENSE](LICENSE) file for details. + +## Contact + +For any inquiries, please contact [Ideal Labs](https://idealabs.network). diff --git a/core/Cargo.toml b/core/Cargo.toml index cee6b81..462aa80 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -2,8 +2,15 @@ name = "murmur-core" version = "0.1.0" edition = "2021" +description = "Murmur core" +documentation = "https://docs.rs/murmur-core" +readme = "README.md" +keywords = ["crypto", "wallet", "keyless"] +categories = ["development-tools", "cryptography"] authors.workspace = true license.workspace = true +repository.workspace = true +homepage.workspace = true [lints] workspace = true diff --git a/core/README.md b/core/README.md index 9efec1d..b058f88 100644 --- a/core/README.md +++ b/core/README.md @@ -4,26 +4,45 @@ This library contains the core implementation of the murmur protocol. This imple ## Build -``` shell +To build the library, use the following command: + +```shell cargo build ``` -The OTP code generator is gated under the "client" feature, so build with: -``` shell +The OTP code generator is gated under the "client" feature. To build with this feature enabled, use: + +```shell cargo build --features "client" ``` ## Test -``` shell +To run the tests, use the following command: + +```shell cargo test ``` The OTP code generator is gated under the "client" feature, so run tests with: -``` shell + +```shell cargo test --features "client" ``` ## Future Work/Notes -- There is an 'otpauth' feature that can be enabled on the totp lib. It allows for the inclusion of an issuer and account_name. We can investigate usage of this in the future. https://github.com/constantoine/totp-rs/blob/da78569b0c233adbce126dbe0c35452340fd3929/src/lib.rs#L160 -- Wallet Update logic: Each murmur wallet is ephemeral, since any MMR must be limited in size. We can use a zkp to prove knowledge of the seed in order to allow the wallet owner to update the wallet by providing a new MMR root. \ No newline at end of file + +- **OTPAuth Feature**: There is an 'otpauth' feature that can be enabled on the totp lib. It allows for the inclusion of an issuer and account_name. We can investigate usage of this in the future. [TOTP Library Reference](https://github.com/constantoine/totp-rs/blob/da78569b0c233adbce126dbe0c35452340fd3929/src/lib.rs#L160) +- **Wallet Update logic**: Each murmur wallet is ephemeral, since any MMR must be limited in size. We can use a zkp to prove knowledge of the seed in order to allow the wallet owner to update the wallet by providing a new MMR root. + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. + +## Contact + +For any inquiries, please contact [Ideal Labs](https://idealabs.network). \ No newline at end of file diff --git a/core/src/lib.rs b/core/src/lib.rs index e47ddb9..430421b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #![cfg_attr(not(feature = "std"), no_std)] //! the murmur core library diff --git a/lib/Cargo.toml b/lib/Cargo.toml index b0df26f..cb1e731 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -2,8 +2,15 @@ name = "murmur-lib" version = "0.1.0" edition = "2021" +description = "Murmur library" +documentation = "https://docs.rs/murmur-lib" +readme = "README.md" +keywords = ["crypto", "wallet", "keyless"] +categories = ["development-tools", "command-line-interface"] authors.workspace = true license.workspace = true +repository.workspace = true +homepage.workspace = true [lib] crate-type = [ diff --git a/lib/README.md b/lib/README.md index 6506c64..d7312b4 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,51 +1,88 @@ -# murmur-lib +# Murmur Lib An implementation of the Murmur protocol and corresponding CLI. This implements the Murmur protocol for usage with the Ideal network's randomness beacon. Specifically, it uses [TinyBLS377](https://docs.rs/w3f-bls/latest/w3f_bls/engine/type.TinyBLS377.html) and constructs basic identities which are deterministic based on block number. ## Setup To setup a dev environment: -- run a local [IDN solochain node](https://github.com/ideal-lab5/etf) -- [generate chain metadata](#generate-metadata) + +1. Run a local [IDN solochain node](https://github.com/ideal-lab5/etf) +2. [Generate chain metadata](#generate-metadata) ### Build -`cargo build` +To build the project, use the following command: + +```shell +cargo build +``` ### CLI Usage ##### Create a wallet -``` shell -# generate a wallet valid for the next 1000 blocks +To generate a wallet valid for the next 1000 blocks, use: + +```shell ./target/debug/murmur new --name test --seed my_secret_key --validity 100 ``` ##### Execute a balance transfer -``` shell -# send a balance transfer +To send a balance transfer, use: + +```shell ./target/debug/murmur execute --name test --seed my_secret_key --to CuqfkE3QieYPAWPpwiygDufmyrKecDcVCF7PN1psaLEn8yr --amount 100_000_000 ``` ## Test -`cargo test` +To run the tests, use the following command: +```shell +cargo test +``` ## Generate Metadata -``` shell -# clone and build the node +To run the tests, use the following command: + +1. Clone and build the node: + +```shell git clone git@github.com:ideal-lab5/etf.git cd etf cargo +stable build -# run a local node +``` + +2. Run a local node: + +```shell ./target/debug/node --tmp --dev --alice --unsafe-rpc-external --rpc-cors all -# use subxt to prepare metadata +``` + +3. Prepare metadata using `subxt`: + +```shel cd /path/to/otp-wallet/ mkdir artifacts cargo install subxt-cli -# Download and save all of the metadata: +``` + +4. Download and save all of the metadata: + +```shell subxt metadata > ./artifacts/metadata.scale -``` \ No newline at end of file +``` + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. + +## Contact + +For any inquiries, please contact [Ideal Labs](https://idealabs.network). diff --git a/lib/src/bin/murmur/main.rs b/lib/src/bin/murmur/main.rs index 59f99fa..5337c2d 100644 --- a/lib/src/bin/murmur/main.rs +++ b/lib/src/bin/murmur/main.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + use clap::{Parser, Subcommand}; use murmur_lib::{ create, etf, idn_connect, prepare_execute, BlockNumber, BoundedVec, MurmurStore, RuntimeCall, @@ -102,12 +103,8 @@ async fn main() -> Result<(), Box> { } // 2. create mmr - let create_data = create( - args.seed.as_bytes().to_vec(), - schedule, - round_pubkey_bytes, - ) - .map_err(|_| CLIError::MurmurCreationFailed)?; + let create_data = create(args.seed.as_bytes().to_vec(), schedule, round_pubkey_bytes) + .map_err(|_| CLIError::MurmurCreationFailed)?; // 3. add to storage write_mmr_store(create_data.mmr_store.clone(), MMR_STORE_FILEPATH); diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 611560e..ad4742e 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -2,6 +2,7 @@ name = "murmur-test-utils" version = "0.1.0" edition = "2021" +description = "Murmur test utils" authors.workspace = true license.workspace = true diff --git a/test-utils/README.md b/test-utils/README.md index 1f3ffd5..53ec9ac 100644 --- a/test-utils/README.md +++ b/test-utils/README.md @@ -1,3 +1,15 @@ # Murmur test utilities -Various test utilities for murmur. \ No newline at end of file +Various test utilities for murmur. + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. + +## Contact + +For any inquiries, please contact [Ideal Labs](https://idealabs.network). diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index bea82b2..69a239d 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #![no_std] //! various utilities helpful for testing From 298d69966f46224d4a10109e51e8f29ce71175d3 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 16 Oct 2024 18:26:31 +0200 Subject: [PATCH 08/11] docs: add readme and license everywhere --- core/LICENSE | 52 ++++++++++++++++++++++++++++++++++++++++ core/README.md | 2 +- docs/murmur/LICENSE | 52 ++++++++++++++++++++++++++++++++++++++++ docs/murmur/README.md | 14 ++++++++++- docs/murmur/package.json | 5 ++-- lib/LICENSE | 52 ++++++++++++++++++++++++++++++++++++++++ lib/README.md | 2 +- test-utils/LICENSE | 52 ++++++++++++++++++++++++++++++++++++++++ test-utils/README.md | 4 ++-- 9 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 core/LICENSE create mode 100644 docs/murmur/LICENSE create mode 100644 lib/LICENSE create mode 100644 test-utils/LICENSE diff --git a/core/LICENSE b/core/LICENSE new file mode 100644 index 0000000..d70a3dd --- /dev/null +++ b/core/LICENSE @@ -0,0 +1,52 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/core/README.md b/core/README.md index b058f88..635fe6c 100644 --- a/core/README.md +++ b/core/README.md @@ -41,7 +41,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. ## Contact diff --git a/docs/murmur/LICENSE b/docs/murmur/LICENSE new file mode 100644 index 0000000..d70a3dd --- /dev/null +++ b/docs/murmur/LICENSE @@ -0,0 +1,52 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/docs/murmur/README.md b/docs/murmur/README.md index 8ada79f..da48e99 100644 --- a/docs/murmur/README.md +++ b/docs/murmur/README.md @@ -1,6 +1,6 @@ # Murmur Docs -This is the official documentation for the murmur protocol. +This is the official documentation for the Murmur protocol. This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. @@ -41,3 +41,15 @@ $ GIT_USER= yarn deploy ``` If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. + +## Contact + +For any inquiries, please contact [Ideal Labs](https://idealabs.network). \ No newline at end of file diff --git a/docs/murmur/package.json b/docs/murmur/package.json index 04fc41a..6e22022 100644 --- a/docs/murmur/package.json +++ b/docs/murmur/package.json @@ -1,7 +1,8 @@ { - "name": "murmur", - "version": "0.0.0", + "name": "murmur-docs", + "version": "0.1.0", "private": true, + "license": "Apache-2.0", "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", diff --git a/lib/LICENSE b/lib/LICENSE new file mode 100644 index 0000000..d70a3dd --- /dev/null +++ b/lib/LICENSE @@ -0,0 +1,52 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/lib/README.md b/lib/README.md index d7312b4..3c12b9a 100644 --- a/lib/README.md +++ b/lib/README.md @@ -81,7 +81,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. ## Contact diff --git a/test-utils/LICENSE b/test-utils/LICENSE new file mode 100644 index 0000000..d70a3dd --- /dev/null +++ b/test-utils/LICENSE @@ -0,0 +1,52 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/test-utils/README.md b/test-utils/README.md index 53ec9ac..f69d721 100644 --- a/test-utils/README.md +++ b/test-utils/README.md @@ -1,6 +1,6 @@ # Murmur test utilities -Various test utilities for murmur. +Various test utilities for Murmur. ## Contributing @@ -8,7 +8,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. ## Contact From 3d0094d6e6facdcf589a5c172b3a646de85aac50 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 16 Oct 2024 19:48:45 +0200 Subject: [PATCH 09/11] chore: remove license files --- core/LICENSE | 52 ------------------------------------------- core/README.md | 2 +- docs/murmur/LICENSE | 52 ------------------------------------------- docs/murmur/README.md | 2 +- lib/LICENSE | 52 ------------------------------------------- lib/README.md | 2 +- test-utils/LICENSE | 52 ------------------------------------------- test-utils/README.md | 2 +- 8 files changed, 4 insertions(+), 212 deletions(-) delete mode 100644 core/LICENSE delete mode 100644 docs/murmur/LICENSE delete mode 100644 lib/LICENSE delete mode 100644 test-utils/LICENSE diff --git a/core/LICENSE b/core/LICENSE deleted file mode 100644 index d70a3dd..0000000 --- a/core/LICENSE +++ /dev/null @@ -1,52 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - You must give any other recipients of the Work or Derivative Works a copy of this License; and - You must cause any modified files to carry prominent notices stating that You changed the files; and - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/core/README.md b/core/README.md index 635fe6c..b058f88 100644 --- a/core/README.md +++ b/core/README.md @@ -41,7 +41,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. ## Contact diff --git a/docs/murmur/LICENSE b/docs/murmur/LICENSE deleted file mode 100644 index d70a3dd..0000000 --- a/docs/murmur/LICENSE +++ /dev/null @@ -1,52 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - You must give any other recipients of the Work or Derivative Works a copy of this License; and - You must cause any modified files to carry prominent notices stating that You changed the files; and - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/docs/murmur/README.md b/docs/murmur/README.md index da48e99..17080ba 100644 --- a/docs/murmur/README.md +++ b/docs/murmur/README.md @@ -48,7 +48,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. ## Contact diff --git a/lib/LICENSE b/lib/LICENSE deleted file mode 100644 index d70a3dd..0000000 --- a/lib/LICENSE +++ /dev/null @@ -1,52 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - You must give any other recipients of the Work or Derivative Works a copy of this License; and - You must cause any modified files to carry prominent notices stating that You changed the files; and - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/lib/README.md b/lib/README.md index 3c12b9a..d7312b4 100644 --- a/lib/README.md +++ b/lib/README.md @@ -81,7 +81,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. ## Contact diff --git a/test-utils/LICENSE b/test-utils/LICENSE deleted file mode 100644 index d70a3dd..0000000 --- a/test-utils/LICENSE +++ /dev/null @@ -1,52 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - You must give any other recipients of the Work or Derivative Works a copy of this License; and - You must cause any modified files to carry prominent notices stating that You changed the files; and - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/test-utils/README.md b/test-utils/README.md index f69d721..c32c05f 100644 --- a/test-utils/README.md +++ b/test-utils/README.md @@ -8,7 +8,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](./LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. ## Contact From cd9cf9896351c539972dd2e88efb582648e12d45 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 16 Oct 2024 19:50:41 +0200 Subject: [PATCH 10/11] fix: readme link --- docs/murmur/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/murmur/README.md b/docs/murmur/README.md index 17080ba..14f0a32 100644 --- a/docs/murmur/README.md +++ b/docs/murmur/README.md @@ -48,7 +48,7 @@ Contributions are welcome! Please open an issue or submit a pull request. ## License -This project is licensed under the Apache-2.0. See the [LICENSE](../LICENSE) file for details. +This project is licensed under the Apache-2.0. See the [LICENSE](../../LICENSE) file for details. ## Contact From fc035339f390e9dfffd15db7e3f5f15f3122380b Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Thu, 17 Oct 2024 13:38:38 +0200 Subject: [PATCH 11/11] chore: fmt --- .github/workflows/rust.yml | 19 +- core/src/murmur.rs | 806 ++++++++++++++++++------------------- core/src/otp.rs | 91 ++--- core/src/types.rs | 32 +- lib/src/bin/murmur/main.rs | 245 ++++++----- lib/src/lib.rs | 330 +++++++-------- test-utils/src/lib.rs | 22 +- 7 files changed, 734 insertions(+), 811 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 38ac38b..61d8125 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,21 +2,24 @@ name: Rust on: push: - branches: [ "main", "dev" ] + branches: ["main", "dev"] pull_request: - branches: [ "main", "dev" ] + branches: ["main", "dev"] env: CARGO_TERM_COLOR: always jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - uses: actions/checkout@v4 + - name: Install Rust + run: rustup update stable + - name: Check formatting + run: cargo fmt -- --check + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose diff --git a/core/src/murmur.rs b/core/src/murmur.rs index 8f32a4f..abe1cdb 100644 --- a/core/src/murmur.rs +++ b/core/src/murmur.rs @@ -15,14 +15,12 @@ */ //! The murmur protocol implementation -//! use alloc::{collections::BTreeMap, vec, vec::Vec}; #[cfg(feature = "client")] use crate::otp::BOTPGenerator; -use ark_std::rand::SeedableRng; -use ark_std::rand::{CryptoRng, Rng}; +use ark_std::rand::{CryptoRng, Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; #[cfg(feature = "client")] @@ -33,9 +31,9 @@ use ark_serialize::CanonicalSerialize; use crate::types::*; use ckb_merkle_mountain_range::{ - helper::leaf_index_to_pos, - util::{MemMMR, MemStore}, - MerkleProof, + helper::leaf_index_to_pos, + util::{MemMMR, MemStore}, + MerkleProof, }; use codec::{Decode, Encode}; use etf_crypto_primitives::{encryption::tlock::*, ibe::fullident::Identity}; @@ -45,454 +43,426 @@ use w3f_bls::{DoublePublicKey, EngineBLS}; /// Error types for murmur wallet usage #[derive(Debug, PartialEq)] pub enum Error { - /// An error occurred when executing a call - ExecuteError, - /// An error occurred when creating a murmur wallet - MMRError, - InconsistentStore, - /// No leaf could be identified in the MMR at the specified position - NoLeafFound, - /// No ciphertext could be identified for the block within the current murmur store - NoCiphertextFound, - /// There was an error when executing timelock encryption (is the ciphertext too large?) - TlockFailed, - /// The buffer does not have enough space allocated - InvalidBufferSize, - /// The seed was invalid - InvalidSeed, - /// The public key was invalid (could not be decoded) - InvalidPubkey, - /// The key derivation failed - KeyDerivationFailed, + /// An error occurred when executing a call + ExecuteError, + /// An error occurred when creating a murmur wallet + MMRError, + InconsistentStore, + /// No leaf could be identified in the MMR at the specified position + NoLeafFound, + /// No ciphertext could be identified for the block within the current murmur store + NoCiphertextFound, + /// There was an error when executing timelock encryption (is the ciphertext too large?) + TlockFailed, + /// The buffer does not have enough space allocated + InvalidBufferSize, + /// The seed was invalid + InvalidSeed, + /// The public key was invalid (could not be decoded) + InvalidPubkey, + /// The key derivation failed + KeyDerivationFailed, } /// The murmur store contains minimal data required to use a murmur wallet #[cfg(feature = "client")] #[derive(Clone, serde::Serialize, serde::Deserialize, Encode, Decode)] pub struct MurmurStore { - /// A map of block numbers to leaf positions in the mmr - pub metadata: BTreeMap, - /// The root of the mmr - pub root: Leaf, + /// A map of block numbers to leaf positions in the mmr + pub metadata: BTreeMap, + /// The root of the mmr + pub root: Leaf, } #[cfg(feature = "client")] impl MurmurStore { - /// Create a new Murmur store - /// - /// * `seed`: An any-length seed (i.e. password) - /// * `block_schedule`: The blocks for which OTP codes will be generated - /// * `ephemeral_msk`: Any 32 bytes - /// * `round_public_key`: The IDN beacon's public key - /// - pub fn new>( - mut seed: Vec, - block_schedule: Vec, - mut ephemeral_msk: [u8; 32], - round_public_key: DoublePublicKey, - ) -> Result { - let totp = build_generator(seed.clone())?; - seed.zeroize(); - let mut metadata = BTreeMap::new(); - - let store = MemStore::default(); - let mut mmr = MemMMR::<_, MergeLeaves>::new(0, store); - - for i in &block_schedule { - let otp_code = totp.generate(*i); - let identity = I::build_identity(*i); - - // we need to seed a new rng here - let mut hasher = sha3::Sha3_256::default(); - hasher.update(ephemeral_msk.to_vec().clone()); - hasher.update(otp_code.as_bytes().to_vec().clone()); - let hash = hasher.finalize(); - - let ephem_rng = ChaCha20Rng::from_seed(hash.into()); - let ct_bytes = timelock_encrypt::( - identity, - round_public_key.1, - ephemeral_msk, - otp_code.as_bytes(), - ephem_rng, - )?; - let leaf = Leaf(ct_bytes.clone()); - // Q: How can I test this? - // https://github.com/nervosnetwork/merkle-mountain-range/blob/9e77d3ef81ddfdd9b7dd9583762582e859849dde/src/mmr.rs#L60 - let _pos = mmr.push(leaf).map_err(|_| Error::InconsistentStore)?; - metadata.insert(*i, ct_bytes); - } - - ephemeral_msk.zeroize(); - let root = mmr.get_root().map_err(|_| Error::InconsistentStore)?; - - Ok(MurmurStore { metadata, root }) - } - - /// Build data required (proof and commitment) to execute a valid call from a murmur wallet - /// - /// * `seed`: The seed used to create the mmr - /// * `when`: The block number when the wallet is being used (or will be) - /// * `call_data`: The call to be executed with the wallet (at `when`) - /// - pub fn execute( - &self, - mut seed: Vec, - when: BlockNumber, - call_data: Vec, - ) -> Result<(MerkleProof, Vec, Ciphertext, u64), Error> { - if let Some(ciphertext) = self.metadata.get(&when) { - let commitment = MurmurStore::commit(seed.clone(), when, &call_data.clone())?; - seed.zeroize(); - let idx = get_key_index(&self.metadata, &when) - .expect("The key must exist within the metadata."); - let pos = leaf_index_to_pos(idx as u64); - let mmr = self.to_mmr()?; - let proof = mmr - .gen_proof(vec![pos]) - .map_err(|_| Error::InconsistentStore)?; - return Ok((proof, commitment, ciphertext.clone(), pos)); - } - - Err(Error::NoCiphertextFound) - } - - /// Generate a commitment (hash) to commit to executing a call at a specific block number - /// - /// * `seed`: The seed used to generated the MMR - /// * `when`: The block number when the commitment is verifiable - /// * `data`: The data to commit to - /// - fn commit(mut seed: Vec, when: BlockNumber, data: &[u8]) -> Result, Error> { - let botp = build_generator(seed.clone())?; - seed.zeroize(); - let otp_code = botp.generate(when); - - let mut hasher = sha3::Sha3_256::default(); - hasher.update(otp_code.as_bytes()); - hasher.update(data); - Ok(hasher.finalize().to_vec()) - } - - /// Builds an mmr from the mmr store - /// - /// * `mmr`: a MemMMR instance (to be populated) - /// - fn to_mmr(&self) -> Result, Error> { - let store = MemStore::default(); - let mut mmr = MemMMR::<_, MergeLeaves>::new(0, store); - for (_block_number, ciphertext) in self.metadata.clone() { - mmr.push(Leaf(ciphertext)) - .map_err(|_| Error::InconsistentStore)?; - } - - Ok(mmr) - } + /// Create a new Murmur store + /// + /// * `seed`: An any-length seed (i.e. password) + /// * `block_schedule`: The blocks for which OTP codes will be generated + /// * `ephemeral_msk`: Any 32 bytes + /// * `round_public_key`: The IDN beacon's public key + pub fn new>( + mut seed: Vec, + block_schedule: Vec, + mut ephemeral_msk: [u8; 32], + round_public_key: DoublePublicKey, + ) -> Result { + let totp = build_generator(seed.clone())?; + seed.zeroize(); + let mut metadata = BTreeMap::new(); + + let store = MemStore::default(); + let mut mmr = MemMMR::<_, MergeLeaves>::new(0, store); + + for i in &block_schedule { + let otp_code = totp.generate(*i); + let identity = I::build_identity(*i); + + // we need to seed a new rng here + let mut hasher = sha3::Sha3_256::default(); + hasher.update(ephemeral_msk.to_vec().clone()); + hasher.update(otp_code.as_bytes().to_vec().clone()); + let hash = hasher.finalize(); + + let ephem_rng = ChaCha20Rng::from_seed(hash.into()); + let ct_bytes = timelock_encrypt::( + identity, + round_public_key.1, + ephemeral_msk, + otp_code.as_bytes(), + ephem_rng, + )?; + let leaf = Leaf(ct_bytes.clone()); + // Q: How can I test this? + // https://github.com/nervosnetwork/merkle-mountain-range/blob/9e77d3ef81ddfdd9b7dd9583762582e859849dde/src/mmr.rs#L60 + let _pos = mmr.push(leaf).map_err(|_| Error::InconsistentStore)?; + metadata.insert(*i, ct_bytes); + } + + ephemeral_msk.zeroize(); + let root = mmr.get_root().map_err(|_| Error::InconsistentStore)?; + + Ok(MurmurStore { metadata, root }) + } + + /// Build data required (proof and commitment) to execute a valid call from a murmur wallet + /// + /// * `seed`: The seed used to create the mmr + /// * `when`: The block number when the wallet is being used (or will be) + /// * `call_data`: The call to be executed with the wallet (at `when`) + pub fn execute( + &self, + mut seed: Vec, + when: BlockNumber, + call_data: Vec, + ) -> Result<(MerkleProof, Vec, Ciphertext, u64), Error> { + if let Some(ciphertext) = self.metadata.get(&when) { + let commitment = MurmurStore::commit(seed.clone(), when, &call_data.clone())?; + seed.zeroize(); + let idx = get_key_index(&self.metadata, &when) + .expect("The key must exist within the metadata."); + let pos = leaf_index_to_pos(idx as u64); + let mmr = self.to_mmr()?; + let proof = mmr.gen_proof(vec![pos]).map_err(|_| Error::InconsistentStore)?; + return Ok((proof, commitment, ciphertext.clone(), pos)); + } + + Err(Error::NoCiphertextFound) + } + + /// Generate a commitment (hash) to commit to executing a call at a specific block number + /// + /// * `seed`: The seed used to generated the MMR + /// * `when`: The block number when the commitment is verifiable + /// * `data`: The data to commit to + fn commit(mut seed: Vec, when: BlockNumber, data: &[u8]) -> Result, Error> { + let botp = build_generator(seed.clone())?; + seed.zeroize(); + let otp_code = botp.generate(when); + + let mut hasher = sha3::Sha3_256::default(); + hasher.update(otp_code.as_bytes()); + hasher.update(data); + Ok(hasher.finalize().to_vec()) + } + + /// Builds an mmr from the mmr store + /// + /// * `mmr`: a MemMMR instance (to be populated) + fn to_mmr(&self) -> Result, Error> { + let store = MemStore::default(); + let mut mmr = MemMMR::<_, MergeLeaves>::new(0, store); + for (_block_number, ciphertext) in self.metadata.clone() { + mmr.push(Leaf(ciphertext)).map_err(|_| Error::InconsistentStore)?; + } + + Ok(mmr) + } } #[cfg(feature = "client")] /// Timelock encryption helper function pub fn timelock_encrypt( - identity: Identity, - pk: E::PublicKeyGroup, - ephemeral_msk: [u8; 32], - message: &[u8], - rng: R, + identity: Identity, + pk: E::PublicKeyGroup, + ephemeral_msk: [u8; 32], + message: &[u8], + rng: R, ) -> Result, Error> { - let ciphertext = - tle::(pk, ephemeral_msk, message, identity, rng).map_err(|_| Error::TlockFailed)?; - let mut ct_bytes = Vec::new(); - ciphertext - .serialize_compressed(&mut ct_bytes) - .map_err(|_| Error::InvalidBufferSize)?; - Ok(ct_bytes) + let ciphertext = + tle::(pk, ephemeral_msk, message, identity, rng).map_err(|_| Error::TlockFailed)?; + let mut ct_bytes = Vec::new(); + ciphertext + .serialize_compressed(&mut ct_bytes) + .map_err(|_| Error::InvalidBufferSize)?; + Ok(ct_bytes) } /// Build a block-otp generator from the seed #[cfg(feature = "client")] fn build_generator(mut seed: Vec) -> Result { - let mut hasher = sha3::Sha3_256::default(); - hasher.update(&seed); - seed.zeroize(); - let hash = hasher.finalize(); - BOTPGenerator::new(hash.to_vec()).map_err(|_| Error::InvalidSeed) + let mut hasher = sha3::Sha3_256::default(); + hasher.update(&seed); + seed.zeroize(); + let hash = hasher.finalize(); + BOTPGenerator::new(hash.to_vec()).map_err(|_| Error::InvalidSeed) } // verify the correctness of execution parameters pub fn verify( - root: Leaf, - proof: MerkleProof, - hash: Vec, - ciphertext: Vec, - otp: Vec, - aux_data: Vec, - pos: u64, + root: Leaf, + proof: MerkleProof, + hash: Vec, + ciphertext: Vec, + otp: Vec, + aux_data: Vec, + pos: u64, ) -> bool { - let mut validity = proof - .verify(root, vec![(pos, Leaf(ciphertext))]) - .unwrap_or(false); + let mut validity = proof.verify(root, vec![(pos, Leaf(ciphertext))]).unwrap_or(false); - if validity { - let mut hasher = sha3::Sha3_256::default(); - hasher.update(otp); - hasher.update(aux_data); - let expected_hash = hasher.finalize(); + if validity { + let mut hasher = sha3::Sha3_256::default(); + hasher.update(otp); + hasher.update(aux_data); + let expected_hash = hasher.finalize(); - validity = validity && expected_hash.to_vec() == hash; - } + validity = validity && expected_hash.to_vec() == hash; + } - validity + validity } /// get the index of a key in a BTreeMap pub fn get_key_index(b: &BTreeMap, key: &K) -> Option { - b.keys().position(|k| k == key) + b.keys().position(|k| k == key) } #[cfg(test)] mod tests { - use super::*; - use ark_std::rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - use rand_core::OsRng; - use w3f_bls::{DoublePublicKeyScheme, TinyBLS377}; - - pub struct DummyIdBuilder; - impl IdentityBuilder for DummyIdBuilder { - fn build_identity(at: BlockNumber) -> Identity { - Identity::new(&[at as u8]) - } - } - - #[cfg(feature = "client")] - #[test] - pub fn it_can_generate_mmr_data_store() { - let mut rng = ChaCha20Rng::seed_from_u64(0); - let keypair = w3f_bls::KeypairVT::::generate(&mut rng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let seed = vec![1, 2, 3]; - let schedule = vec![1, 2, 3]; - - let hk = hkdf::Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let murmur_store = MurmurStore::new::( - seed.clone(), - schedule.clone(), - ephem_msk, - double_public, - ) - .unwrap(); - - assert!(murmur_store.metadata.keys().len() == 3); - } - - #[cfg(feature = "client")] - #[test] - pub fn it_can_generate_valid_output_and_verify_it() { - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let seed = vec![1, 2, 3]; - let schedule = vec![ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - ]; - - let aux_data = vec![2, 3, 4, 5]; - - let hk = hkdf::Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let murmur_store = MurmurStore::new::( - seed.clone(), - schedule.clone(), - ephem_msk, - double_public, - ) - .unwrap(); - - // the block number when this would execute - let when = 1; - - let root = murmur_store.root.clone(); - let (proof, commitment, ciphertext, pos) = murmur_store - .execute(seed.clone(), when, aux_data.clone()) - .unwrap(); - - // sanity check - assert!(proof - .verify(root.clone(), vec![(pos, Leaf(ciphertext.clone()))]) - .unwrap()); - - // in practice, the otp code would be timelock decrypted - // but for testing purposes, we will just calculate the expected one now - let botp = build_generator(seed.clone()).unwrap(); - let otp_code = botp.generate(when); - - assert!(verify( - root, - proof, - commitment, - ciphertext, - otp_code.as_bytes().to_vec(), - aux_data, - pos, - )); - } - - #[cfg(feature = "client")] - #[test] - pub fn it_fails_to_generate_execute_output_when_ciphertext_dne() { - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let seed = vec![1, 2, 3]; - let schedule = vec![1, 2, 3, 4, 5]; - - let aux_data = vec![2, 3, 4, 5]; - - let hk = hkdf::Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let murmur_store = MurmurStore::new::( - seed.clone(), - schedule.clone(), - ephem_msk, - double_public, - ) - .unwrap(); - - // the block number when this would execute - let when = 1000; - - match murmur_store.execute(seed.clone(), when, aux_data.clone()) { - Ok(_) => panic!("There should be an error"), - Err(e) => assert_eq!(e, Error::NoCiphertextFound), - } - } - - #[cfg(feature = "client")] - #[test] - pub fn it_fails_on_verify_bad_aux_data() { - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let seed = vec![1, 2, 3]; - let schedule = vec![1, 2, 3]; - - let aux_data = vec![2, 3, 4, 5]; - - let hk = hkdf::Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let murmur_store = MurmurStore::new::( - seed.clone(), - schedule.clone(), - ephem_msk, - double_public, - ) - .unwrap(); - - // the block number when this would execute - let when = 1; - let root = murmur_store.root.clone(); - let (proof, commitment, ciphertext, pos) = murmur_store - .execute(seed.clone(), when, aux_data.clone()) - .unwrap(); - - // in practice, the otp code would be timelock decrypted - // but for testing purposes, we will just calculate the expected one now - let botp = build_generator(seed.clone()).unwrap(); - let otp_code = botp.generate(when); - - let bad_aux = vec![2, 3, 13, 3]; - assert!(!verify( - root, - proof, - commitment, - ciphertext, - otp_code.as_bytes().to_vec(), - bad_aux, - pos, - )); - } - - #[test] - pub fn it_fails_on_verify_bad_proof() { - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let other_double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - - let seed = vec![1, 2, 3]; - let schedule = vec![1, 2, 3]; - let other_schedule = vec![1, 2, 3, 4, 5]; - - let aux_data = vec![2, 3, 4, 5]; - - let hk = hkdf::Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let murmur_store = MurmurStore::new::( - seed.clone(), - schedule.clone(), - ephem_msk, - double_public, - ) - .unwrap(); - - let other_murmur_store = MurmurStore::new::( - seed.clone(), - other_schedule.clone(), - ephem_msk, - other_double_public, - ) - .unwrap(); - - // the block number when this would execute - let when = 1; - let root = murmur_store.root.clone(); - let (proof, commitment, ciphertext, pos) = other_murmur_store - .execute(seed.clone(), when, aux_data.clone()) - .unwrap(); - - // in practice, the otp code would be timelock decrypted - // but for testing purposes, we will just calculate the expected one now - let botp = build_generator(seed.clone()).unwrap(); - let otp_code = botp.generate(when); - assert!(!verify( - root, - proof, - commitment, - ciphertext, - otp_code.as_bytes().to_vec(), - aux_data, - pos, - )); - } + use super::*; + use ark_std::rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + use rand_core::OsRng; + use w3f_bls::{DoublePublicKeyScheme, TinyBLS377}; + + pub struct DummyIdBuilder; + impl IdentityBuilder for DummyIdBuilder { + fn build_identity(at: BlockNumber) -> Identity { + Identity::new(&[at as u8]) + } + } + + #[cfg(feature = "client")] + #[test] + pub fn it_can_generate_mmr_data_store() { + let mut rng = ChaCha20Rng::seed_from_u64(0); + let keypair = w3f_bls::KeypairVT::::generate(&mut rng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let seed = vec![1, 2, 3]; + let schedule = vec![1, 2, 3]; + + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let murmur_store = MurmurStore::new::( + seed.clone(), + schedule.clone(), + ephem_msk, + double_public, + ) + .unwrap(); + + assert!(murmur_store.metadata.keys().len() == 3); + } + + #[cfg(feature = "client")] + #[test] + pub fn it_can_generate_valid_output_and_verify_it() { + let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let seed = vec![1, 2, 3]; + let schedule = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + + let aux_data = vec![2, 3, 4, 5]; + + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let murmur_store = MurmurStore::new::( + seed.clone(), + schedule.clone(), + ephem_msk, + double_public, + ) + .unwrap(); + + // the block number when this would execute + let when = 1; + + let root = murmur_store.root.clone(); + let (proof, commitment, ciphertext, pos) = + murmur_store.execute(seed.clone(), when, aux_data.clone()).unwrap(); + + // sanity check + assert!(proof.verify(root.clone(), vec![(pos, Leaf(ciphertext.clone()))]).unwrap()); + + // in practice, the otp code would be timelock decrypted + // but for testing purposes, we will just calculate the expected one now + let botp = build_generator(seed.clone()).unwrap(); + let otp_code = botp.generate(when); + + assert!(verify( + root, + proof, + commitment, + ciphertext, + otp_code.as_bytes().to_vec(), + aux_data, + pos, + )); + } + + #[cfg(feature = "client")] + #[test] + pub fn it_fails_to_generate_execute_output_when_ciphertext_dne() { + let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let seed = vec![1, 2, 3]; + let schedule = vec![1, 2, 3, 4, 5]; + + let aux_data = vec![2, 3, 4, 5]; + + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let murmur_store = MurmurStore::new::( + seed.clone(), + schedule.clone(), + ephem_msk, + double_public, + ) + .unwrap(); + + // the block number when this would execute + let when = 1000; + + match murmur_store.execute(seed.clone(), when, aux_data.clone()) { + Ok(_) => panic!("There should be an error"), + Err(e) => assert_eq!(e, Error::NoCiphertextFound), + } + } + + #[cfg(feature = "client")] + #[test] + pub fn it_fails_on_verify_bad_aux_data() { + let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let seed = vec![1, 2, 3]; + let schedule = vec![1, 2, 3]; + + let aux_data = vec![2, 3, 4, 5]; + + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let murmur_store = MurmurStore::new::( + seed.clone(), + schedule.clone(), + ephem_msk, + double_public, + ) + .unwrap(); + + // the block number when this would execute + let when = 1; + let root = murmur_store.root.clone(); + let (proof, commitment, ciphertext, pos) = + murmur_store.execute(seed.clone(), when, aux_data.clone()).unwrap(); + + // in practice, the otp code would be timelock decrypted + // but for testing purposes, we will just calculate the expected one now + let botp = build_generator(seed.clone()).unwrap(); + let otp_code = botp.generate(when); + + let bad_aux = vec![2, 3, 13, 3]; + assert!(!verify( + root, + proof, + commitment, + ciphertext, + otp_code.as_bytes().to_vec(), + bad_aux, + pos, + )); + } + + #[test] + pub fn it_fails_on_verify_bad_proof() { + let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let other_double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + + let seed = vec![1, 2, 3]; + let schedule = vec![1, 2, 3]; + let other_schedule = vec![1, 2, 3, 4, 5]; + + let aux_data = vec![2, 3, 4, 5]; + + let hk = hkdf::Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let murmur_store = MurmurStore::new::( + seed.clone(), + schedule.clone(), + ephem_msk, + double_public, + ) + .unwrap(); + + let other_murmur_store = MurmurStore::new::( + seed.clone(), + other_schedule.clone(), + ephem_msk, + other_double_public, + ) + .unwrap(); + + // the block number when this would execute + let when = 1; + let root = murmur_store.root.clone(); + let (proof, commitment, ciphertext, pos) = + other_murmur_store.execute(seed.clone(), when, aux_data.clone()).unwrap(); + + // in practice, the otp code would be timelock decrypted + // but for testing purposes, we will just calculate the expected one now + let botp = build_generator(seed.clone()).unwrap(); + let otp_code = botp.generate(when); + assert!(!verify( + root, + proof, + commitment, + ciphertext, + otp_code.as_bytes().to_vec(), + aux_data, + pos, + )); + } } diff --git a/core/src/otp.rs b/core/src/otp.rs index 1e86787..f0d5217 100644 --- a/core/src/otp.rs +++ b/core/src/otp.rs @@ -14,71 +14,64 @@ * limitations under the License. */ -use totp_rs::{Secret, TOTP, Algorithm}; -use alloc::{ - vec::Vec, - string::String, -}; +use alloc::{string::String, vec::Vec}; +use totp_rs::{Algorithm, Secret, TOTP}; #[derive(Debug)] pub enum OTPError { - /// The secret size is too large - InvalidSecret, + /// The secret size is too large + InvalidSecret, } /// A block based otp generator pub struct BOTPGenerator { - /// The time-based otp generator - totp: TOTP + /// The time-based otp generator + totp: TOTP, } impl BOTPGenerator { - /// Create a new BOTP generator with the given seed - /// - /// * `seed`: The seed used to generate OTP codes - /// - pub fn new(seed: Vec) -> Result { - let secret = Secret::Raw(seed.to_vec()).to_bytes() - .map_err(|_| OTPError::InvalidSecret)?; - let totp = TOTP::new( - Algorithm::SHA256, // algorithm - 6, // num digits - 1, // skew - 1, // step - secret // secret - ).map_err(|_| OTPError::InvalidSecret)?; + /// Create a new BOTP generator with the given seed + /// + /// * `seed`: The seed used to generate OTP codes + pub fn new(seed: Vec) -> Result { + let secret = Secret::Raw(seed.to_vec()).to_bytes().map_err(|_| OTPError::InvalidSecret)?; + let totp = TOTP::new( + Algorithm::SHA256, // algorithm + 6, // num digits + 1, // skew + 1, // step + secret, // secret + ) + .map_err(|_| OTPError::InvalidSecret)?; - Ok(BOTPGenerator { totp }) - } - - /// Generate an otp code - /// - /// * `block_height`: The block for which the code is valid - /// - pub fn generate(&self, block_height: u32) -> String { - self.totp.generate(block_height as u64) - } + Ok(BOTPGenerator { totp }) + } + /// Generate an otp code + /// + /// * `block_height`: The block for which the code is valid + pub fn generate(&self, block_height: u32) -> String { + self.totp.generate(block_height as u64) + } } #[cfg(test)] mod tests { - use super::*; - use alloc::vec; - - #[test] - pub fn it_can_generate_otp_codes_with_valid_seed() { - let botp = BOTPGenerator::new([1;32].to_vec()).unwrap(); - let otp_min = botp.generate(0); - assert!(otp_min.len() == 6); + use super::*; + use alloc::vec; - let otp_max = botp.generate(u32::MAX); - assert!(otp_max.len() == 6); - } + #[test] + pub fn it_can_generate_otp_codes_with_valid_seed() { + let botp = BOTPGenerator::new([1; 32].to_vec()).unwrap(); + let otp_min = botp.generate(0); + assert!(otp_min.len() == 6); - #[test] - pub fn it_fails_to_build_otp_generator_with_invalid_seed() { - assert!(BOTPGenerator::new(vec![1]).is_err()); - } + let otp_max = botp.generate(u32::MAX); + assert!(otp_max.len() == 6); + } -} \ No newline at end of file + #[test] + pub fn it_fails_to_build_otp_generator_with_invalid_seed() { + assert!(BOTPGenerator::new(vec![1]).is_err()); + } +} diff --git a/core/src/types.rs b/core/src/types.rs index d9b2c63..4145723 100644 --- a/core/src/types.rs +++ b/core/src/types.rs @@ -30,33 +30,33 @@ pub type Ciphertext = Vec; /// A leaf in the MMR /// The payload is an opaque, any-length vec #[derive( - Eq, PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize, Encode, Decode, + Eq, PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize, Encode, Decode, )] pub struct Leaf(pub Vec); impl From> for Leaf { - fn from(data: Vec) -> Self { - let mut hasher = sha3::Sha3_256::default(); - hasher.update(&data); - let hash = hasher.finalize(); - Leaf(hash.to_vec().into()) - } + fn from(data: Vec) -> Self { + let mut hasher = sha3::Sha3_256::default(); + hasher.update(&data); + let hash = hasher.finalize(); + Leaf(hash.to_vec().into()) + } } /// Merge leaves together with a sha256 hasher #[derive(Debug)] pub struct MergeLeaves; impl Merge for MergeLeaves { - type Item = Leaf; - fn merge(lhs: &Self::Item, rhs: &Self::Item) -> MMRResult { - let mut hasher = sha3::Sha3_256::default(); - hasher.update(&lhs.0); - hasher.update(&rhs.0); - let hash = hasher.finalize(); - Ok(Leaf(hash.to_vec().into())) - } + type Item = Leaf; + fn merge(lhs: &Self::Item, rhs: &Self::Item) -> MMRResult { + let mut hasher = sha3::Sha3_256::default(); + hasher.update(&lhs.0); + hasher.update(&rhs.0); + let hash = hasher.finalize(); + Ok(Leaf(hash.to_vec().into())) + } } /// Something that builds unique identities (e.g. using crypto hash function) for any block number pub trait IdentityBuilder { - fn build_identity(at: BlockNumber) -> Identity; + fn build_identity(at: BlockNumber) -> Identity; } diff --git a/lib/src/bin/murmur/main.rs b/lib/src/bin/murmur/main.rs index 5337c2d..50b4caa 100644 --- a/lib/src/bin/murmur/main.rs +++ b/lib/src/bin/murmur/main.rs @@ -16,11 +16,10 @@ use clap::{Parser, Subcommand}; use murmur_lib::{ - create, etf, idn_connect, prepare_execute, BlockNumber, BoundedVec, MurmurStore, RuntimeCall, + create, etf, idn_connect, prepare_execute, BlockNumber, BoundedVec, MurmurStore, RuntimeCall, }; use sp_core::crypto::Ss58Codec; -use std::fs::File; -use std::time::Instant; +use std::{fs::File, time::Instant}; use subxt_signer::sr25519::dev; use thiserror::Error; @@ -29,54 +28,54 @@ use thiserror::Error; #[command(author, version, about, long_about = None)] #[command(propagate_version = true)] struct Cli { - #[command(subcommand)] - commands: Commands, + #[command(subcommand)] + commands: Commands, } #[derive(Subcommand)] enum Commands { - /// create a new murmur wallet - New(WalletCreationDetails), - /// dispatch (proxy) a call to a murmur wallet - Execute(WalletExecuteDetails), + /// create a new murmur wallet + New(WalletCreationDetails), + /// dispatch (proxy) a call to a murmur wallet + Execute(WalletExecuteDetails), } #[derive(Parser)] struct WalletCreationDetails { - #[arg(long, short)] - name: String, - #[arg(long, short)] - seed: String, - #[clap(long, short)] - validity: u32, + #[arg(long, short)] + name: String, + #[arg(long, short)] + seed: String, + #[clap(long, short)] + validity: u32, } #[derive(Parser)] struct WalletExecuteDetails { - #[arg(long, short)] - name: String, - #[arg(long, short)] - seed: String, - #[arg(long, short)] - to: String, - #[arg(short, long, value_parser = clap::value_parser!(u128))] - amount: u128, + #[arg(long, short)] + name: String, + #[arg(long, short)] + seed: String, + #[arg(long, short)] + to: String, + #[arg(short, long, value_parser = clap::value_parser!(u128))] + amount: u128, } #[derive(Error, Debug)] pub enum CLIError { - #[error("invalid public key")] - InvalidPubkey, - #[error("invalid address")] - InvalidRecipient, - #[error("could not parse input to a u128")] - InvalidSendAmount, - #[error("something went wrong while creating the MMR")] - MurmurCreationFailed, - #[error("something went wrong while executing the MMR wallet")] - MurmurExecutionFailed, - #[error("the murmur store is corrupted or empty")] - CorruptedMurmurStore, + #[error("invalid public key")] + InvalidPubkey, + #[error("invalid address")] + InvalidRecipient, + #[error("could not parse input to a u128")] + InvalidSendAmount, + #[error("something went wrong while creating the MMR")] + MurmurCreationFailed, + #[error("something went wrong while executing the MMR wallet")] + MurmurExecutionFailed, + #[error("the murmur store is corrupted or empty")] + CorruptedMurmurStore, } /// the mmr_store file location @@ -85,103 +84,97 @@ pub const MMR_STORE_FILEPATH: &str = "mmr_store"; #[tokio::main] async fn main() -> Result<(), Box> { - let cli = Cli::parse(); - let before = Instant::now(); - - let (client, current_block_number, round_pubkey_bytes) = idn_connect().await?; - - match &cli.commands { - Commands::New(args) => { - println!("🏭 Murmur: Generating Merkle mountain range"); - - // 1. prepare block schedule - let mut schedule: Vec = Vec::new(); - for i in 2..args.validity + 2 { - // wallet is 'active' in 2 blocks - let next_block_number: BlockNumber = current_block_number + i; - schedule.push(next_block_number); - } - - // 2. create mmr - let create_data = create(args.seed.as_bytes().to_vec(), schedule, round_pubkey_bytes) - .map_err(|_| CLIError::MurmurCreationFailed)?; - - // 3. add to storage - write_mmr_store(create_data.mmr_store.clone(), MMR_STORE_FILEPATH); - - // 4. build the call - let call = etf::tx().murmur().create( - create_data.root, - create_data.size, - BoundedVec(args.name.as_bytes().to_vec()), - ); - - // 5. sign and send the call - client - .tx() - .sign_and_submit_then_watch_default(&call, &dev::alice()) - .await?; - - println!("✅ MMR proxy account creation successful!"); - } - Commands::Execute(args) => { - // 1. build proxied call - let from_ss58 = sp_core::crypto::AccountId32::from_ss58check(&args.to) - .map_err(|_| CLIError::InvalidRecipient)?; - let bytes: &[u8] = from_ss58.as_ref(); - let from_ss58_sized: [u8; 32] = - bytes.try_into().map_err(|_| CLIError::InvalidRecipient)?; - let to = subxt::utils::AccountId32::from(from_ss58_sized); - let balance_transfer_call = - RuntimeCall::Balances(etf::balances::Call::transfer_allow_death { - dest: subxt::utils::MultiAddress::<_, u32>::from(to), - value: args.amount, - }); - - // 2. load the MMR store - let store: MurmurStore = load_mmr_store(MMR_STORE_FILEPATH)?; - println!("💾 Recovered Murmur store from local file"); - - // 3. get the proxy data - let proxy_data = prepare_execute( - args.seed.as_bytes().to_vec(), - current_block_number + 1, - store, - &balance_transfer_call, - ) - .map_err(|_| CLIError::MurmurExecutionFailed)?; - - // 4. build the call - let call = etf::tx().murmur().proxy( - BoundedVec(args.name.as_bytes().to_vec()), - proxy_data.position, - proxy_data.hash, - proxy_data.ciphertext, - proxy_data.proof_items, - proxy_data.size, - balance_transfer_call, - ); - // 5. sign and send the call - client - .tx() - .sign_and_submit_then_watch_default(&call, &dev::alice()) - .await?; - } - } - println!("Elapsed time: {:.2?}", before.elapsed()); - Ok(()) + let cli = Cli::parse(); + let before = Instant::now(); + + let (client, current_block_number, round_pubkey_bytes) = idn_connect().await?; + + match &cli.commands { + Commands::New(args) => { + println!("🏭 Murmur: Generating Merkle mountain range"); + + // 1. prepare block schedule + let mut schedule: Vec = Vec::new(); + for i in 2..args.validity + 2 { + // wallet is 'active' in 2 blocks + let next_block_number: BlockNumber = current_block_number + i; + schedule.push(next_block_number); + } + + // 2. create mmr + let create_data = create(args.seed.as_bytes().to_vec(), schedule, round_pubkey_bytes) + .map_err(|_| CLIError::MurmurCreationFailed)?; + + // 3. add to storage + write_mmr_store(create_data.mmr_store.clone(), MMR_STORE_FILEPATH); + + // 4. build the call + let call = etf::tx().murmur().create( + create_data.root, + create_data.size, + BoundedVec(args.name.as_bytes().to_vec()), + ); + + // 5. sign and send the call + client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?; + + println!("✅ MMR proxy account creation successful!"); + }, + Commands::Execute(args) => { + // 1. build proxied call + let from_ss58 = sp_core::crypto::AccountId32::from_ss58check(&args.to) + .map_err(|_| CLIError::InvalidRecipient)?; + let bytes: &[u8] = from_ss58.as_ref(); + let from_ss58_sized: [u8; 32] = + bytes.try_into().map_err(|_| CLIError::InvalidRecipient)?; + let to = subxt::utils::AccountId32::from(from_ss58_sized); + let balance_transfer_call = + RuntimeCall::Balances(etf::balances::Call::transfer_allow_death { + dest: subxt::utils::MultiAddress::<_, u32>::from(to), + value: args.amount, + }); + + // 2. load the MMR store + let store: MurmurStore = load_mmr_store(MMR_STORE_FILEPATH)?; + println!("💾 Recovered Murmur store from local file"); + + // 3. get the proxy data + let proxy_data = prepare_execute( + args.seed.as_bytes().to_vec(), + current_block_number + 1, + store, + &balance_transfer_call, + ) + .map_err(|_| CLIError::MurmurExecutionFailed)?; + + // 4. build the call + let call = etf::tx().murmur().proxy( + BoundedVec(args.name.as_bytes().to_vec()), + proxy_data.position, + proxy_data.hash, + proxy_data.ciphertext, + proxy_data.proof_items, + proxy_data.size, + balance_transfer_call, + ); + // 5. sign and send the call + client.tx().sign_and_submit_then_watch_default(&call, &dev::alice()).await?; + }, + } + println!("Elapsed time: {:.2?}", before.elapsed()); + Ok(()) } /// read an MMR from a file fn load_mmr_store(path: &str) -> Result { - let mmr_store_file = File::open(path).expect("Unable to open file"); - let data: MurmurStore = - serde_cbor::from_reader(mmr_store_file).map_err(|_| CLIError::CorruptedMurmurStore)?; - Ok(data) + let mmr_store_file = File::open(path).expect("Unable to open file"); + let data: MurmurStore = + serde_cbor::from_reader(mmr_store_file).map_err(|_| CLIError::CorruptedMurmurStore)?; + Ok(data) } /// Write the MMR data to a file fn write_mmr_store(mmr_store: MurmurStore, path: &str) { - let mmr_store_file = File::create(path).expect("It should create the file"); - serde_cbor::to_writer(mmr_store_file, &mmr_store).unwrap(); + let mmr_store_file = File::create(path).expect("It should create the file"); + serde_cbor::to_writer(mmr_store_file, &mmr_store).unwrap(); } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 9d26338..633cb60 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -19,17 +19,17 @@ use hkdf::Hkdf; use murmur_core::types::{Identity, IdentityBuilder}; use serde::Serialize; use subxt::{ - backend::rpc::RpcClient, client::OnlineClient, config::SubstrateConfig, ext::codec::Encode, + backend::rpc::RpcClient, client::OnlineClient, config::SubstrateConfig, ext::codec::Encode, }; use w3f_bls::{DoublePublicKey, SerializableToBytes, TinyBLS377}; use zeroize::Zeroize; pub use etf::runtime_types::{ - bounded_collections::bounded_vec::BoundedVec, node_template_runtime::RuntimeCall, + bounded_collections::bounded_vec::BoundedVec, node_template_runtime::RuntimeCall, }; pub use murmur_core::{ - murmur::{Error, MurmurStore}, - types::BlockNumber, + murmur::{Error, MurmurStore}, + types::BlockNumber, }; // Generate an interface that we can use from the node's metadata. @@ -40,36 +40,37 @@ pub mod etf {} #[derive(Debug)] pub struct BasicIdBuilder; impl IdentityBuilder for BasicIdBuilder { - fn build_identity(when: BlockNumber) -> Identity { - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let commitment = Commitment { - payload, - block_number: when, - validator_set_id: 0, // TODO: how to ensure correct validator set ID is used? could just always set to 1 for now, else set input param. - }; - Identity::new(&commitment.encode()) - } + fn build_identity(when: BlockNumber) -> Identity { + let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); + let commitment = Commitment { + payload, + block_number: when, + validator_set_id: 0, /* TODO: how to ensure correct validator set ID is used? could + * just always set to 1 for now, else set input param. */ + }; + Identity::new(&commitment.encode()) + } } #[derive(Serialize)] /// Data needed to build a valid call for creating a murmur wallet. pub struct CreateData { - /// The root of the MMR - pub root: Vec, - /// The size of the MMR - pub size: u64, - pub mmr_store: MurmurStore, + /// The root of the MMR + pub root: Vec, + /// The size of the MMR + pub size: u64, + pub mmr_store: MurmurStore, } #[derive(Serialize)] /// Data needed to build a valid call for a proxied execution. pub struct ProxyData { - pub position: u64, - /// The hash of the commitment - pub hash: Vec, - pub ciphertext: Vec, - pub proof_items: Vec>, - pub size: u64, + pub position: u64, + /// The hash of the commitment + pub hash: Vec, + pub ciphertext: Vec, + pub proof_items: Vec>, + pub size: u64, } /// Create a new MMR and return the data needed to build a valid call for creating a murmur wallet. @@ -77,35 +78,30 @@ pub struct ProxyData { /// * `seed`: The seed used to generate otp codes /// * `block_schedule`: A list of block numbers when the wallet will be executable /// * `round_pubkey_bytes`: The Ideal Network randomness beacon public key -/// pub fn create( - mut seed: Vec, - block_schedule: Vec, - round_pubkey_bytes: Vec, + mut seed: Vec, + block_schedule: Vec, + round_pubkey_bytes: Vec, ) -> Result { - // Derive ephem_msk from seed using HKDF - let hk = Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk) - .map_err(|_| Error::KeyDerivationFailed)?; - - let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes) - .map_err(|_| Error::InvalidPubkey)?; - let mmr_store = MurmurStore::new::( - seed.clone(), - block_schedule.clone(), - ephem_msk, - round_pubkey, - )?; - ephem_msk.zeroize(); - seed.zeroize(); - let root = mmr_store.root.clone(); - - Ok(CreateData { - root: root.0, - size: mmr_store.metadata.len() as u64, - mmr_store, - }) + // Derive ephem_msk from seed using HKDF + let hk = Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk) + .map_err(|_| Error::KeyDerivationFailed)?; + + let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes) + .map_err(|_| Error::InvalidPubkey)?; + let mmr_store = MurmurStore::new::( + seed.clone(), + block_schedule.clone(), + ephem_msk, + round_pubkey, + )?; + ephem_msk.zeroize(); + seed.zeroize(); + let root = mmr_store.root.clone(); + + Ok(CreateData { root: root.0, size: mmr_store.metadata.len() as u64, mmr_store }) } /// Return the data needed for the immediate execution of the proxied call. @@ -113,37 +109,27 @@ pub fn create( /// * `when`: The block number when OTP codeds should be generated /// * `store`: A murmur store /// * `call`: Proxied call. Any valid runtime call -/// -// Note to self: in the future, we can consider ways to prune the murmurstore as OTP codes are consumed -// for example, we can take the next values from the map, reducing storage to 0 over time -// However, to do this we need to think of a way to prove it with a merkle proof -// my thought is that we would have a subtree, so first we prove that the subtree is indeed in the parent MMR -// then we prove that the specific leaf is in the subtree. -// We could potentially use that idea as a way to optimize the execute function in general. Rather than -// loading the entire MMR into memory, we really only need to load a minimal subtree containing the leaf we want to consume -// -> add this to the 'future work' section later +// Note to self: in the future, we can consider ways to prune the murmurstore as OTP codes are +// consumed for example, we can take the next values from the map, reducing storage to 0 over +// time However, to do this we need to think of a way to prove it with a merkle proof +// my thought is that we would have a subtree, so first we prove that the subtree is indeed in +// the parent MMR then we prove that the specific leaf is in the subtree. +// We could potentially use that idea as a way to optimize the execute function in general. Rather +// than loading the entire MMR into memory, we really only need to load a minimal subtree +// containing the leaf we want to consume -> add this to the 'future work' section later pub fn prepare_execute( - mut seed: Vec, - when: BlockNumber, - store: MurmurStore, - call: &RuntimeCall, + mut seed: Vec, + when: BlockNumber, + store: MurmurStore, + call: &RuntimeCall, ) -> Result { - let (proof, commitment, ciphertext, pos) = store.execute(seed.clone(), when, call.encode())?; - seed.zeroize(); - let size = proof.mmr_size(); - let proof_items: Vec> = proof - .proof_items() - .iter() - .map(|leaf| leaf.0.clone()) - .collect::>(); + let (proof, commitment, ciphertext, pos) = store.execute(seed.clone(), when, call.encode())?; + seed.zeroize(); + let size = proof.mmr_size(); + let proof_items: Vec> = + proof.proof_items().iter().map(|leaf| leaf.0.clone()).collect::>(); - Ok(ProxyData { - position: pos, - hash: commitment, - ciphertext, - proof_items, - size, - }) + Ok(ProxyData { position: pos, hash: commitment, ciphertext, proof_items, size }) } /// Async connection to the Ideal Network @@ -151,111 +137,91 @@ pub fn prepare_execute( /// else error if unreachable pub async fn idn_connect( ) -> Result<(OnlineClient, BlockNumber, Vec), Box> { - println!("🎲 Connecting to Ideal network (local node)"); - let ws_url = std::env::var("WS_URL").unwrap_or_else(|_| { - let fallback_url = "ws://localhost:9944".to_string(); - println!( - "⚠️ WS_URL environment variable not set. Using fallback URL: {}", - fallback_url - ); - fallback_url - }); - - let rpc_client = RpcClient::from_url(&ws_url).await?; - let client = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; - println!("🔗 RPC Client: connection established"); - - // fetch the round public key from etf runtime storage - let round_key_query = subxt::dynamic::storage("Etf", "RoundPublic", ()); - let result = client - .storage() - .at_latest() - .await? - .fetch(&round_key_query) - .await?; - let round_pubkey_bytes = result.unwrap().as_type::>()?; - - println!("🔑 Successfully retrieved the round public key."); - - let current_block = client.blocks().at_latest().await?; - let current_block_number: BlockNumber = current_block.header().number; - println!("🧊 Current block number: #{:?}", current_block_number); - Ok((client, current_block_number, round_pubkey_bytes)) + println!("🎲 Connecting to Ideal network (local node)"); + let ws_url = std::env::var("WS_URL").unwrap_or_else(|_| { + let fallback_url = "ws://localhost:9944".to_string(); + println!("⚠️ WS_URL environment variable not set. Using fallback URL: {}", fallback_url); + fallback_url + }); + + let rpc_client = RpcClient::from_url(&ws_url).await?; + let client = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; + println!("🔗 RPC Client: connection established"); + + // fetch the round public key from etf runtime storage + let round_key_query = subxt::dynamic::storage("Etf", "RoundPublic", ()); + let result = client.storage().at_latest().await?.fetch(&round_key_query).await?; + let round_pubkey_bytes = result.unwrap().as_type::>()?; + + println!("🔑 Successfully retrieved the round public key."); + + let current_block = client.blocks().at_latest().await?; + let current_block_number: BlockNumber = current_block.header().number; + println!("🧊 Current block number: #{:?}", current_block_number); + Ok((client, current_block_number, round_pubkey_bytes)) } #[cfg(test)] mod tests { - use super::*; - - #[test] - pub fn it_can_create_an_mmr_store() { - let seed = b"seed".to_vec(); - let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; - let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); - let create_data = create( - seed.clone(), - block_schedule.clone(), - double_public_bytes.clone(), - ) - .unwrap(); - - let hk = Hkdf::::new(None, &seed); - let mut ephem_msk = [0u8; 32]; - hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); - - let mmr_store = MurmurStore::new::( - seed, - block_schedule, - ephem_msk, - DoublePublicKey::::from_bytes(&double_public_bytes).unwrap(), - ) - .unwrap(); - - assert_eq!(create_data.mmr_store.root, mmr_store.root); - assert_eq!(create_data.size, 7); - } - - #[test] - pub fn it_can_prepare_valid_execution_call_data() { - let seed = b"seed".to_vec(); - let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; - let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); - let create_data = - create(seed.clone(), block_schedule, double_public_bytes).unwrap(); - - let bob = subxt_signer::sr25519::dev::bob().public_key(); - let balance_transfer_call = - &etf::runtime_types::node_template_runtime::RuntimeCall::Balances( - etf::balances::Call::transfer_allow_death { - dest: subxt::utils::MultiAddress::<_, u32>::from(bob), - value: 1, - }, - ); - - let proxy_data = prepare_execute( - seed.clone(), - 1, - create_data.mmr_store.clone(), - balance_transfer_call, - ) - .unwrap(); - - let (proof, commitment, ciphertext, _pos) = create_data - .mmr_store - .execute(seed.clone(), 1, balance_transfer_call.encode()) - .unwrap(); - - let size = proof.mmr_size(); - let proof_items: Vec> = proof - .proof_items() - .iter() - .map(|leaf| leaf.0.clone()) - .collect::>(); - - assert_eq!(proxy_data.position, 0); - assert_eq!(proxy_data.hash, commitment); - assert_eq!(proxy_data.ciphertext, ciphertext); - assert_eq!(proxy_data.proof_items, proof_items); - assert_eq!(proxy_data.size, size); - } + use super::*; + + #[test] + pub fn it_can_create_an_mmr_store() { + let seed = b"seed".to_vec(); + let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; + let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); + let create_data = + create(seed.clone(), block_schedule.clone(), double_public_bytes.clone()).unwrap(); + + let hk = Hkdf::::new(None, &seed); + let mut ephem_msk = [0u8; 32]; + hk.expand(b"ephemeral key", &mut ephem_msk).unwrap(); + + let mmr_store = MurmurStore::new::( + seed, + block_schedule, + ephem_msk, + DoublePublicKey::::from_bytes(&double_public_bytes).unwrap(), + ) + .unwrap(); + + assert_eq!(create_data.mmr_store.root, mmr_store.root); + assert_eq!(create_data.size, 7); + } + + #[test] + pub fn it_can_prepare_valid_execution_call_data() { + let seed = b"seed".to_vec(); + let block_schedule = vec![1, 2, 3, 4, 5, 6, 7]; + let double_public_bytes = murmur_test_utils::get_dummy_beacon_pubkey(); + let create_data = create(seed.clone(), block_schedule, double_public_bytes).unwrap(); + + let bob = subxt_signer::sr25519::dev::bob().public_key(); + let balance_transfer_call = + &etf::runtime_types::node_template_runtime::RuntimeCall::Balances( + etf::balances::Call::transfer_allow_death { + dest: subxt::utils::MultiAddress::<_, u32>::from(bob), + value: 1, + }, + ); + + let proxy_data = + prepare_execute(seed.clone(), 1, create_data.mmr_store.clone(), balance_transfer_call) + .unwrap(); + + let (proof, commitment, ciphertext, _pos) = create_data + .mmr_store + .execute(seed.clone(), 1, balance_transfer_call.encode()) + .unwrap(); + + let size = proof.mmr_size(); + let proof_items: Vec> = + proof.proof_items().iter().map(|leaf| leaf.0.clone()).collect::>(); + + assert_eq!(proxy_data.position, 0); + assert_eq!(proxy_data.hash, commitment); + assert_eq!(proxy_data.ciphertext, ciphertext); + assert_eq!(proxy_data.proof_items, proof_items); + assert_eq!(proxy_data.size, size); + } } diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 69a239d..0e8e54d 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -18,10 +18,10 @@ //! various utilities helpful for testing -use w3f_bls::{DoublePublicKey, DoublePublicKeyScheme, TinyBLS377}; -use rand_core::OsRng; -use ark_serialize::CanonicalSerialize; use alloc::vec::Vec; +use ark_serialize::CanonicalSerialize; +use rand_core::OsRng; +use w3f_bls::{DoublePublicKey, DoublePublicKeyScheme, TinyBLS377}; extern crate alloc; @@ -30,12 +30,10 @@ pub use murmur_core::otp::BOTPGenerator; pub use murmur_core::murmur::MurmurStore; pub fn get_dummy_beacon_pubkey() -> Vec { - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let double_public: DoublePublicKey = DoublePublicKey( - keypair.into_public_key_in_signature_group().0, - keypair.public.0, - ); - let mut bytes = Vec::new(); - double_public.serialize_compressed(&mut bytes).unwrap(); - bytes -} \ No newline at end of file + let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); + let double_public: DoublePublicKey = + DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); + let mut bytes = Vec::new(); + double_public.serialize_compressed(&mut bytes).unwrap(); + bytes +}