diff --git a/crates/common/src/keys.rs b/crates/common/src/keys.rs index 77704d92..65a91807 100644 --- a/crates/common/src/keys.rs +++ b/crates/common/src/keys.rs @@ -97,9 +97,8 @@ impl TryFrom for VerifyingKey { /// * `Ok(VerifyingKey)` if the conversion was successful. /// * `Err` if the input is invalid or the conversion failed. fn try_from(s: String) -> std::result::Result { - let bytes = engine - .decode(s) - .map_err(|e| anyhow!("Failed to decode base64 string: {}", e))?; + let bytes = + engine.decode(s).map_err(|e| anyhow!("Failed to decode base64 string: {}", e))?; match bytes.len() { 32 => Ok(VerifyingKey::Ed25519(bytes)), diff --git a/crates/common/src/test_utils.rs b/crates/common/src/test_utils.rs index 2ed4831c..45925127 100644 --- a/crates/common/src/test_utils.rs +++ b/crates/common/src/test_utils.rs @@ -86,9 +86,7 @@ impl TestTreeState { return Err(anyhow!("{:?} already contained in tree", account.key_hash)); } - let proof = self - .tree - .process_operation(&account.hashchain.last().unwrap().operation)?; + let proof = self.tree.process_operation(&account.hashchain.last().unwrap().operation)?; if let Proof::Insert(insert_proof) = proof { self.inserted_keys.insert(account.key_hash); return Ok(insert_proof); @@ -101,9 +99,7 @@ impl TestTreeState { return Err(anyhow!("{:?} not found in tree", account.key_hash)); } - let proof = self - .tree - .process_operation(&account.hashchain.last().unwrap().operation)?; + let proof = self.tree.process_operation(&account.hashchain.last().unwrap().operation)?; if let Proof::Update(update_proof) = proof { return Ok(update_proof); } @@ -186,16 +182,12 @@ impl Default for TestTreeState { pub fn create_random_insert(state: &mut TestTreeState, rng: &mut StdRng) -> InsertProof { loop { - let random_string: String = (0..10) - .map(|_| rng.sample(rand::distributions::Alphanumeric) as char) - .collect(); + let random_string: String = + (0..10).map(|_| rng.sample(rand::distributions::Alphanumeric) as char).collect(); let sk = create_mock_signing_key(); - let (_, service) = state - .services - .iter() - .nth(rng.gen_range(0..state.services.len())) - .unwrap(); + let (_, service) = + state.services.iter().nth(rng.gen_range(0..state.services.len())).unwrap(); let hc = create_new_hashchain(random_string.as_str(), &sk, service.clone()); //Hashchain::new(random_string); let key = hc.get_keyhash(); @@ -214,11 +206,7 @@ pub fn create_random_update(state: &mut TestTreeState, rng: &mut StdRng) -> Upda panic!("No keys have been inserted yet. Cannot perform update."); } - let key = *state - .inserted_keys - .iter() - .nth(rng.gen_range(0..state.inserted_keys.len())) - .unwrap(); + let key = *state.inserted_keys.iter().nth(rng.gen_range(0..state.inserted_keys.len())).unwrap(); let Found(mut hc, _) = state.tree.get(key).unwrap() else { panic!("No response found for key. Cannot perform update."); @@ -241,13 +229,9 @@ pub fn create_random_update(state: &mut TestTreeState, rng: &mut StdRng) -> Upda 0, ) .unwrap(); - hc.perform_operation(operation) - .expect("Adding to hashchain should succeed"); + hc.perform_operation(operation).expect("Adding to hashchain should succeed"); - state - .tree - .update(key, hc.last().unwrap().clone()) - .expect("Update should succeed") + state.tree.update(key, hc.last().unwrap().clone()).expect("Update should succeed") } #[cfg(not(feature = "secp256k1"))] diff --git a/crates/common/src/tree.rs b/crates/common/src/tree.rs index 83dac118..74d38752 100644 --- a/crates/common/src/tree.rs +++ b/crates/common/src/tree.rs @@ -49,8 +49,7 @@ pub struct MembershipProof { impl MembershipProof { pub fn verify(&self) -> Result<()> { let value = bincode::serialize(&self.value)?; - self.proof - .verify_existence(self.root.into(), self.key, value) + self.proof.verify_existence(self.root.into(), self.key, value) } } @@ -78,9 +77,7 @@ pub struct InsertProof { impl InsertProof { pub fn verify(&self) -> Result<()> { - self.non_membership_proof - .verify() - .context("Invalid NonMembershipProof")?; + self.non_membership_proof.verify().context("Invalid NonMembershipProof")?; let value = bincode::serialize(&self.value)?; @@ -116,8 +113,7 @@ impl UpdateProof { // Verify existence of old value. // Otherwise, any arbitrary hashchain could be set let old_value = bincode::serialize(&self.old_value)?; - self.inclusion_proof - .verify_existence(self.old_root, self.key, old_value)?; + self.inclusion_proof.verify_existence(self.old_root, self.key, old_value)?; // Append the new entry and verify it's validity let new_hashchain = self.old_value.insert_unsafe(self.new_entry.clone()); @@ -214,9 +210,7 @@ where } pub fn get_current_root(&self) -> Result { - self.jmt - .get_root_hash(self.epoch) - .map_err(|e| anyhow!("Failed to get root hash: {}", e)) + self.jmt.get_root_hash(self.epoch).map_err(|e| anyhow!("Failed to get root hash: {}", e)) } fn serialize_value(value: &Hashchain) -> Result> { @@ -311,10 +305,7 @@ where value.verify_signature( &bincode::serialize( - &new_account_entry - .operation - .without_challenge() - .without_signature(), + &new_account_entry.operation.without_challenge().without_signature(), )?, signature, )?; @@ -448,9 +439,7 @@ mod tests { let service = tree_state.register_service("service_1".to_string()); let account = tree_state.create_account("key_1".to_string(), service.clone()); - let insert_proof = tree_state - .insert_account(service.registration.clone()) - .unwrap(); + let insert_proof = tree_state.insert_account(service.registration.clone()).unwrap(); assert!(insert_proof.verify().is_ok()); let insert_proof = tree_state.insert_account(account.clone()).unwrap(); @@ -485,9 +474,7 @@ mod tests { let account = tree_state.create_account("key_1".to_string(), falsified_service.clone()); - let insert_proof = tree_state - .insert_account(service.registration.clone()) - .unwrap(); + let insert_proof = tree_state.insert_account(service.registration.clone()).unwrap(); assert!(insert_proof.verify().is_ok()); let insert_proof = tree_state.insert_account(account.clone()); @@ -500,9 +487,7 @@ mod tests { let service = tree_state.register_service("service_1".to_string()); let account = tree_state.create_account("key_1".to_string(), service.clone()); - let insert_proof = tree_state - .insert_account(service.registration.clone()) - .unwrap(); + let insert_proof = tree_state.insert_account(service.registration.clone()).unwrap(); assert!(insert_proof.verify().is_ok()); tree_state.insert_account(account.clone()).unwrap(); @@ -517,9 +502,7 @@ mod tests { let service = tree_state.register_service("service_1".to_string()); let mut account = tree_state.create_account("key_1".to_string(), service.clone()); - tree_state - .insert_account(service.registration.clone()) - .unwrap(); + tree_state.insert_account(service.registration.clone()).unwrap(); tree_state.insert_account(account.clone()).unwrap(); // Add a new key @@ -538,9 +521,7 @@ mod tests { let mut tree_state = TestTreeState::default(); let service = tree_state.register_service("service_1".to_string()); let account = tree_state.create_account("key_1".to_string(), service.clone()); - tree_state - .insert_account(service.registration.clone()) - .unwrap(); + tree_state.insert_account(service.registration.clone()).unwrap(); let result = tree_state.update_account(account); assert!(result.is_err()); @@ -577,13 +558,9 @@ mod tests { tree_state.add_key_to_account(&mut account1).unwrap(); tree_state.update_account(account1.clone()).unwrap(); - tree_state - .add_unsigned_data_to_account(b"unsigned", &mut account2) - .unwrap(); + tree_state.add_unsigned_data_to_account(b"unsigned", &mut account2).unwrap(); tree_state.update_account(account2.clone()).unwrap(); - tree_state - .add_signed_data_to_account(b"signed", &mut account2) - .unwrap(); + tree_state.add_signed_data_to_account(b"signed", &mut account2).unwrap(); tree_state.update_account(account2.clone()).unwrap(); let get_result1 = tree_state.tree.get(account1.key_hash); @@ -636,10 +613,7 @@ mod tests { tree_state.insert_account(service.registration).unwrap(); let root_before = tree_state.tree.get_current_root().unwrap(); - tree_state - .tree - .insert(account.key_hash, account.hashchain) - .unwrap(); + tree_state.tree.insert(account.key_hash, account.hashchain).unwrap(); let root_after = tree_state.tree.get_current_root().unwrap(); assert_ne!(root_before, root_after); diff --git a/crates/da/src/lib.rs b/crates/da/src/lib.rs index adf79c71..ce0e6206 100644 --- a/crates/da/src/lib.rs +++ b/crates/da/src/lib.rs @@ -39,10 +39,8 @@ impl FinalizedEpoch { let message = bincode::serialize(&epoch_without_signature) .map_err(|e| anyhow::anyhow!("Failed to serialize epoch: {}", e))?; - let signature = self - .signature - .as_ref() - .ok_or_else(|| anyhow::anyhow!("No signature present"))?; + let signature = + self.signature.as_ref().ok_or_else(|| anyhow::anyhow!("No signature present"))?; let signature_bytes = hex::decode(signature) .map_err(|e| anyhow::anyhow!("Failed to decode signature: {}", e))?; diff --git a/crates/node_types/prover/src/prover/mod.rs b/crates/node_types/prover/src/prover/mod.rs index 120fafd4..a0ffcae7 100644 --- a/crates/node_types/prover/src/prover/mod.rs +++ b/crates/node_types/prover/src/prover/mod.rs @@ -158,8 +158,7 @@ impl Prover { } }; - self.sync_loop(start_height, historical_sync_height, height_rx) - .await + self.sync_loop(start_height, historical_sync_height, height_rx).await } async fn sync_loop( @@ -180,8 +179,7 @@ impl Prover { let mut current_height = start_height; while current_height <= end_height { - self.process_da_height(current_height, &mut buffered_operations, false) - .await?; + self.process_da_height(current_height, &mut buffered_operations, false).await?; // TODO: Race between set_epoch and set_last_synced_height self.db.set_last_synced_height(¤t_height)?; current_height += 1; @@ -201,8 +199,7 @@ impl Prover { height )); } - self.process_da_height(height, &mut buffered_operations, true) - .await?; + self.process_da_height(height, &mut buffered_operations, true).await?; current_height += 1; // TODO: Race between set_epoch and set_last_synced_height - updating these should be a single atomic operation self.db.set_last_synced_height(¤t_height)?; @@ -334,9 +331,8 @@ impl Prover { let new_commitment = self.get_commitment().await?; - let finalized_epoch = self - .prove_epoch(epoch_height, prev_commitment, new_commitment, proofs) - .await?; + let finalized_epoch = + self.prove_epoch(epoch_height, prev_commitment, new_commitment, proofs).await?; self.da.submit_finalized_epoch(finalized_epoch).await?; diff --git a/crates/node_types/prover/src/webserver.rs b/crates/node_types/prover/src/webserver.rs index 325d177d..d51893b3 100644 --- a/crates/node_types/prover/src/webserver.rs +++ b/crates/node_types/prover/src/webserver.rs @@ -132,10 +132,7 @@ async fn update_entry( State(session): State>, Json(operation_input): Json, ) -> impl IntoResponse { - match session - .validate_and_queue_update(&operation_input.operation) - .await - { + match session.validate_and_queue_update(&operation_input.operation).await { Ok(_) => ( StatusCode::OK, "Entry update queued for insertion into next epoch", diff --git a/crates/storage/src/redis.rs b/crates/storage/src/redis.rs index 1ad6ed1a..23beab16 100644 --- a/crates/storage/src/redis.rs +++ b/crates/storage/src/redis.rs @@ -60,9 +60,7 @@ impl RedisConnection { } let client = Client::open(connection_string).map_err(convert_to_connection_error)?; - let connection = client - .get_connection() - .map_err(convert_to_connection_error)?; + let connection = client.get_connection().map_err(convert_to_connection_error)?; Ok(RedisConnection { connection: Mutex::new(connection), @@ -73,9 +71,7 @@ impl RedisConnection { // because rust can not make sure that that's the case, we need to use the 'static lifetime here // (but i dont really know why the issue pops up now and not before, i think we were using the same/similar pattern in the other functions) fn lock_connection(&self) -> Result> { - self.connection - .lock() - .map_err(|_| anyhow!(DatabaseError::LockError)) + self.connection.lock().map_err(|_| anyhow!(DatabaseError::LockError)) } } @@ -156,9 +152,8 @@ impl TreeWriter for RedisConnection { impl Database for RedisConnection { fn get_commitment(&self, epoch: &u64) -> Result { let mut con = self.lock_connection()?; - let redis_value = con - .get::<&str, String>(&format!("commitments:epoch_{}", epoch)) - .map_err(|_| { + let redis_value = + con.get::<&str, String>(&format!("commitments:epoch_{}", epoch)).map_err(|_| { DatabaseError::NotFoundError(format!("commitment from epoch_{}", epoch)) })?; @@ -178,13 +173,12 @@ impl Database for RedisConnection { fn set_last_synced_height(&self, height: &u64) -> Result<()> { let mut con = self.lock_connection()?; - con.set::<&str, &u64, ()>("app_state:sync_height", height) - .map_err(|_| { - anyhow!(DatabaseError::WriteError(format!( - "sync_height: {}", - height - ))) - }) + con.set::<&str, &u64, ()>("app_state:sync_height", height).map_err(|_| { + anyhow!(DatabaseError::WriteError(format!( + "sync_height: {}", + height + ))) + }) } fn get_epoch(&self) -> Result { diff --git a/crates/storage/src/rocksdb.rs b/crates/storage/src/rocksdb.rs index ac426d29..ec0d7946 100644 --- a/crates/storage/src/rocksdb.rs +++ b/crates/storage/src/rocksdb.rs @@ -33,9 +33,8 @@ impl Database for RocksDBConnection { DatabaseError::NotFoundError(format!("commitment from epoch_{}", epoch)) })?; - let value: [u8; 32] = raw_bytes - .try_into() - .expect("commitment digest should always be 32 bytes"); + let value: [u8; 32] = + raw_bytes.try_into().expect("commitment digest should always be 32 bytes"); Ok(Digest(value)) } @@ -57,9 +56,7 @@ impl Database for RocksDBConnection { } fn set_last_synced_height(&self, height: &u64) -> anyhow::Result<()> { - Ok(self - .connection - .put(b"app_state:sync_height", height.to_be_bytes())?) + Ok(self.connection.put(b"app_state:sync_height", height.to_be_bytes())?) } fn get_epoch(&self) -> anyhow::Result { @@ -72,9 +69,7 @@ impl Database for RocksDBConnection { } fn set_epoch(&self, epoch: &u64) -> anyhow::Result<()> { - Ok(self - .connection - .put(b"app_state:epoch", epoch.to_be_bytes())?) + Ok(self.connection.put(b"app_state:epoch", epoch.to_be_bytes())?) } fn flush_database(&self) -> Result<()> { diff --git a/crates/zk/groth16/src/lib.rs b/crates/zk/groth16/src/lib.rs index 13adb532..f805ebb9 100644 --- a/crates/zk/groth16/src/lib.rs +++ b/crates/zk/groth16/src/lib.rs @@ -132,11 +132,7 @@ impl From> for VerifyingKey { delta_g1: G1(verifying_key.delta_g1.to_compressed()), delta_g2: G2(verifying_key.delta_g2.to_compressed()), gamma_g2: G2(verifying_key.gamma_g2.to_compressed()), - ic: verifying_key - .ic - .iter() - .map(|x| G1(x.to_compressed())) - .collect::>(), + ic: verifying_key.ic.iter().map(|x| G1(x.to_compressed())).collect::>(), } } } @@ -169,11 +165,8 @@ impl TryFrom for groth16::VerifyingKey { .gamma_g2 .try_into() .map_err(|e| GeneralError::EncodingError(format!("{}: gamma_g2", e)))?; - let ic = custom_vk - .ic - .into_iter() - .map(|s| s.try_into()) - .collect::>>()?; + let ic = + custom_vk.ic.into_iter().map(|s| s.try_into()).collect::>>()?; Ok(bellman::groth16::VerifyingKey { alpha_g1, diff --git a/crates/zk/groth16/src/merkle_insertion.rs b/crates/zk/groth16/src/merkle_insertion.rs index cb9b94d9..35f62c24 100644 --- a/crates/zk/groth16/src/merkle_insertion.rs +++ b/crates/zk/groth16/src/merkle_insertion.rs @@ -141,18 +141,12 @@ pub fn prove_non_membership>( ) -> Result<(), SynthesisError> { // Ensure that the label of the new leaf node lies between the first element of the path // and its next pointer. This guarantees that no other node with a label between these values exists. - let existing_leaf_label: Scalar = insertion_path[0] - .get_label() - .try_into() - .map_err(|_| SynthesisError::Unsatisfiable)?; - let existing_leaf_next: Scalar = insertion_path[0] - .get_next() - .try_into() - .map_err(|_| SynthesisError::Unsatisfiable)?; - let new_leaf_label: Scalar = new_leaf_node - .label - .try_into() - .map_err(|_| SynthesisError::Unsatisfiable)?; + let existing_leaf_label: Scalar = + insertion_path[0].get_label().try_into().map_err(|_| SynthesisError::Unsatisfiable)?; + let existing_leaf_next: Scalar = + insertion_path[0].get_next().try_into().map_err(|_| SynthesisError::Unsatisfiable)?; + let new_leaf_label: Scalar = + new_leaf_node.label.try_into().map_err(|_| SynthesisError::Unsatisfiable)?; // Enforce: existing_leaf_label < new_leaf_label < existing_leaf_next LessThanCircuit::new(existing_leaf_label, new_leaf_label) diff --git a/crates/zk/nova/src/batch.rs b/crates/zk/nova/src/batch.rs index 290aec3e..25bc1aa9 100644 --- a/crates/zk/nova/src/batch.rs +++ b/crates/zk/nova/src/batch.rs @@ -185,12 +185,8 @@ mod tests { let mut z0_primary = vec![initial_commitment]; // Initial root z0_primary.push(::Scalar::ZERO); // Initial ROM index - z0_primary.extend( - circuit_sequence - .rom - .iter() - .map(|&x| ::Scalar::from(x as u64)), - ); + z0_primary + .extend(circuit_sequence.rom.iter().map(|&x| ::Scalar::from(x as u64))); let z0_secondary = vec![< as Engine>::Scalar>::ONE]; @@ -214,13 +210,9 @@ mod tests { .unwrap() }); - recursive_snark - .prove_step(&pp, &primary_circuit, &secondary_circuit) - .unwrap(); + recursive_snark.prove_step(&pp, &primary_circuit, &secondary_circuit).unwrap(); - recursive_snark - .verify(&pp, &z0_primary, &z0_secondary) - .unwrap(); + recursive_snark.verify(&pp, &z0_primary, &z0_secondary).unwrap(); recursive_snark_option = Some(recursive_snark) } @@ -229,9 +221,7 @@ mod tests { let recursive_snark = recursive_snark_option.unwrap(); - assert!(recursive_snark - .verify(&pp, &z0_primary, &z0_secondary) - .is_ok()); + assert!(recursive_snark.verify(&pp, &z0_primary, &z0_secondary).is_ok()); // Additional assertions let zi_primary = recursive_snark.zi_primary(); @@ -244,9 +234,7 @@ mod tests { ); let final_commitment: ::Scalar = - NovaDigest::new(state.tree.get_commitment().unwrap()) - .to_scalar() - .unwrap(); + NovaDigest::new(state.tree.get_commitment().unwrap()).to_scalar().unwrap(); assert_eq!( zi_primary[0], final_commitment, diff --git a/crates/zk/nova/src/insert.rs b/crates/zk/nova/src/insert.rs index a69b5d63..d69fe599 100644 --- a/crates/zk/nova/src/insert.rs +++ b/crates/zk/nova/src/insert.rs @@ -65,17 +65,13 @@ impl StepCircuit for InsertCircuit< // Allocate the new root let new_root = AllocatedNum::alloc(cs.namespace(|| "new_root"), || { - Digest::new(self.proof.new_root) - .to_scalar() - .map_err(|_| SynthesisError::Unsatisfiable) + Digest::new(self.proof.new_root).to_scalar().map_err(|_| SynthesisError::Unsatisfiable) })?; let new_root_bits = allocate_bits_to_binary_number(cs, self.proof.membership_proof.root_hash().0.to_vec())?; - self.proof - .verify() - .map_err(|_| SynthesisError::Unsatisfiable)?; + self.proof.verify().map_err(|_| SynthesisError::Unsatisfiable)?; // Verify the non-membership proof // verify_non_membership_proof( @@ -85,11 +81,7 @@ impl StepCircuit for InsertCircuit< // &key_bits, // )?; - let leaf = &self - .proof - .membership_proof - .leaf() - .ok_or(SynthesisError::AssignmentMissing)?; + let leaf = &self.proof.membership_proof.leaf().ok_or(SynthesisError::AssignmentMissing)?; verify_membership_proof(cs, &self.proof.membership_proof, new_root_bits, *leaf)?; diff --git a/crates/zk/nova/src/update.rs b/crates/zk/nova/src/update.rs index 043f41da..049f2b48 100644 --- a/crates/zk/nova/src/update.rs +++ b/crates/zk/nova/src/update.rs @@ -82,15 +82,11 @@ where let update_proof = &self.update_proof.update_proof.proofs()[0]; - let leaf = &update_proof - .leaf() - .ok_or(SynthesisError::AssignmentMissing)?; + let leaf = &update_proof.leaf().ok_or(SynthesisError::AssignmentMissing)?; verify_membership_proof(cs, update_proof, old_root_bits, *leaf)?; - self.update_proof - .verify() - .map_err(|_| SynthesisError::Unsatisfiable)?; + self.update_proof.verify().map_err(|_| SynthesisError::Unsatisfiable)?; let mut z_next = vec![new_root]; z_next.push(rom_index_next); diff --git a/crates/zk/nova/src/utils.rs b/crates/zk/nova/src/utils.rs index 1baa7e9b..fc8d047e 100644 --- a/crates/zk/nova/src/utils.rs +++ b/crates/zk/nova/src/utils.rs @@ -98,10 +98,7 @@ pub fn next_rom_index_and_pc>( // Allocate the next pc without checking. // The next iteration will check whether the next pc is valid. let pc_next = AllocatedNum::alloc_infallible(cs.namespace(|| "next pc"), || { - allocated_rom - .get(next_rom_index) - .and_then(|v| v.get_value()) - .unwrap_or(-F::ONE) + allocated_rom.get(next_rom_index).and_then(|v| v.get_value()).unwrap_or(-F::ONE) }); Ok((rom_index_next, pc_next)) @@ -142,10 +139,8 @@ pub fn get_selector_vec_from_index>( // Enforce `target_index - ∑ i * selector[i] = 0`` { - let selected_value = selector - .iter() - .enumerate() - .fold(LinearCombination::zero(), |lc, (i, bit)| { + let selected_value = + selector.iter().enumerate().fold(LinearCombination::zero(), |lc, (i, bit)| { lc + &bit.lc(CS::one(), F::from(i as u64)) }); cs.enforce( @@ -175,10 +170,7 @@ pub fn create_pp() -> PublicParams { ) .unwrap(); - let insert_proof = test_tree - .tree - .insert(account.key_hash, account.hashchain.clone()) - .unwrap(); + let insert_proof = test_tree.tree.insert(account.key_hash, account.hashchain.clone()).unwrap(); test_tree.add_key_to_account(&mut account).unwrap(); @@ -197,10 +189,8 @@ pub fn allocate_bits_to_binary_number, ) -> Result, SynthesisError> { - let bits: Vec = value - .iter() - .flat_map(|byte| (0..8).rev().map(move |i| (byte >> i) & 1 == 1)) - .collect(); + let bits: Vec = + value.iter().flat_map(|byte| (0..8).rev().map(move |i| (byte >> i) & 1 == 1)).collect(); let result: Result, SynthesisError> = bits .into_iter() @@ -435,17 +425,9 @@ fn conditionally_select_vector> #[allow(dead_code)] fn boolvec_to_bytes(value: Vec) -> Vec { - let bits: Vec = value - .iter() - .map(|b| b.get_value().unwrap_or(false)) - .collect(); + let bits: Vec = value.iter().map(|b| b.get_value().unwrap_or(false)).collect(); bits.chunks(8) - .map(|chunk| { - chunk - .iter() - .enumerate() - .fold(0u8, |acc, (i, &bit)| acc | ((bit as u8) << i)) - }) + .map(|chunk| chunk.iter().enumerate().fold(0u8, |acc, (i, &bit)| acc | ((bit as u8) << i))) .collect() }