diff --git a/crates/bloom-filter/src/lib.rs b/crates/bloom-filter/src/lib.rs index 8fdb0210..4a776bfd 100755 --- a/crates/bloom-filter/src/lib.rs +++ b/crates/bloom-filter/src/lib.rs @@ -3,6 +3,7 @@ extern crate alloc; use alloc::boxed::Box; +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::RuntimeDebug; @@ -12,78 +13,95 @@ pub struct BloomFilter(pub [u64; 256]); #[derive(Debug)] pub enum BloomError { - InsertError, - DeleteError, - Overflow, - BinaryError, + InsertError, + DeleteError, + Overflow, + BinaryError, + LengthError, } impl Default for BloomFilter { - fn default() -> Self { - let value: [u64; 256] = [0u64; 256]; - BloomFilter(value) - } + fn default() -> Self { + let value: [u64; 256] = [0u64; 256]; + BloomFilter(value) + } } -impl BloomFilter { - pub fn insert(&mut self, elem: [u8; 256]) -> Result<(), BloomError> { - let mut index: usize = 0; - for value in elem { - if value != 1 && value != 0 { - return Err(BloomError::InsertError); - } - self.0[index] = self.0[index] + value as u64; - index = index + 1; - } - - Ok(()) - } - - pub fn delete(&mut self, elem: [u8; 256]) -> Result<(), BloomError> { - let mut index: usize = 0; - for value in elem { - if value != 1 && value != 0 { - return Err(BloomError::DeleteError); - } - self.0[index] = self.0[index] - value as u64; - index = index + 1; - } - - Ok(()) - } +impl TryFrom> for BloomFilter { + type Error = BloomError; + + fn try_from(value: Vec) -> Result { + if value.len() != 256 { + return Err(BloomError::LengthError); + } + + let array: [u64; 256] = match value.try_into() { + Ok(arr) => arr, + Err(_) => return Err(BloomError::BinaryError), + }; + + Ok(BloomFilter(array)) + } } +impl BloomFilter { + pub fn insert(&mut self, elem: [u8; 256]) -> Result<(), BloomError> { + let mut index: usize = 0; + for value in elem { + if value != 1 && value != 0 { + return Err(BloomError::InsertError); + } + self.0[index] = self.0[index] + value as u64; + index = index + 1; + } + + Ok(()) + } + + pub fn delete(&mut self, elem: [u8; 256]) -> Result<(), BloomError> { + let mut index: usize = 0; + for value in elem { + if value != 1 && value != 0 { + return Err(BloomError::DeleteError); + } + self.0[index] = self.0[index] - value as u64; + index = index + 1; + } + + Ok(()) + } +} pub fn binary(data: [u8; 64]) -> Result, BloomError> { - let mut elem: Box<[u8; 256]> = Box::new([0u8; 256]); - let mut index: usize = 0; - for value in data.iter() { - let binary = match value { - b'0' => [0, 0, 0, 0], - b'1' => [0, 0, 0, 1], - b'2' => [0, 0, 1, 0], - b'3' => [0, 0, 1, 1], - b'4' => [0, 1, 0, 0], - b'5' => [0, 1, 0, 1], - b'6' => [0, 1, 1, 0], - b'7' => [0, 1, 1, 1], - b'8' => [1, 0, 0, 0], - b'9' => [1, 0, 0, 1], - b'a' => [1, 0, 1, 0], - b'b' => [1, 0, 1, 1], - b'c' => [1, 1, 0, 0], - b'd' => [1, 1, 0, 1], - b'e' => [1, 1, 1, 0], - b'f' => [1, 1, 1, 1], - _ => return Err(BloomError::BinaryError), - }; - - elem[index * 4] = binary[0]; - elem[index * 4 + 1] = binary[1]; - elem[index * 4 + 2] = binary[2]; - elem[index * 4 + 3] = binary[3]; - - index = index + 1; - } - Ok(elem) + let mut elem: Box<[u8; 256]> = Box::new([0u8; 256]); + let mut index: usize = 0; + for value in data.iter() { + let binary = match value { + b'0' => [0, 0, 0, 0], + b'1' => [0, 0, 0, 1], + b'2' => [0, 0, 1, 0], + b'3' => [0, 0, 1, 1], + b'4' => [0, 1, 0, 0], + b'5' => [0, 1, 0, 1], + b'6' => [0, 1, 1, 0], + b'7' => [0, 1, 1, 1], + b'8' => [1, 0, 0, 0], + b'9' => [1, 0, 0, 1], + b'a' => [1, 0, 1, 0], + b'b' => [1, 0, 1, 1], + b'c' => [1, 1, 0, 0], + b'd' => [1, 1, 0, 1], + b'e' => [1, 1, 1, 0], + b'f' => [1, 1, 1, 1], + _ => return Err(BloomError::BinaryError), + }; + + elem[index * 4] = binary[0]; + elem[index * 4 + 1] = binary[1]; + elem[index * 4 + 2] = binary[2]; + elem[index * 4 + 3] = binary[3]; + + index = index + 1; + } + Ok(elem) } diff --git a/crates/ces-pdp/src/lib.rs b/crates/ces-pdp/src/lib.rs index 9c24d5c2..80276ce7 100644 --- a/crates/ces-pdp/src/lib.rs +++ b/crates/ces-pdp/src/lib.rs @@ -204,7 +204,7 @@ impl Keys { "The size of file {:?} is {}, which cannot be divisible by {} blocks", name, file_size, n_blocks )), - }) + }); }; let each_chunks_size = file_size / n_blocks; @@ -218,10 +218,11 @@ impl Keys { let _ = f.seek(SeekFrom::Start(offset)); match f.read_exact(&mut chunks) { Ok(_) => {}, - Err(e) => + Err(e) => { return Err(PDPError { error_code: FailCode::InternalError(format!("Fail in read file :{:?}", e.to_string())), - }), + }) + }, }; let tx = tx.clone(); @@ -284,7 +285,7 @@ impl Keys { "The size of file {:?} is {}, which cannot be divisible by {} blocks", name, file_size, n_blocks )), - }) + }); }; let each_chunks_size = file_size / n_blocks; @@ -422,6 +423,22 @@ impl Keys { Ok(sigma.to_string()) } + pub fn aggr_append_proof(&self, mut aggr_sigma: String, mut sub_sigma: String) -> Result { + let n = num_bigint::BigUint::from_bytes_be(&self.pkey.n().to_bytes_be()); + if aggr_sigma == "".to_string() { + aggr_sigma = "1".to_string() + } + let mut sigma = num_bigint::BigUint::from_str(&aggr_sigma) + .map_err(|e| PDPError { error_code: FailCode::InternalError(e.to_string()) })?; + + let mut sub_sigma = num_bigint::BigUint::from_str(&aggr_sigma) + .map_err(|e| PDPError { error_code: FailCode::InternalError(e.to_string()) })?; + sigma = sigma * sub_sigma; + sigma = sigma.mod_floor(&n); + + Ok(sigma.to_string()) + } + pub fn verify( &self, u: String, @@ -579,7 +596,7 @@ pub fn gen_chall(n: u64) -> Vec { q.v = v.to_bytes_be(); challenge[index] = q; index += 1; - break + break; } } } diff --git a/crates/cestory/api/proto/podr2-api.proto b/crates/cestory/api/proto/podr2-api.proto index 31773bce..70cab6b4 100644 --- a/crates/cestory/api/proto/podr2-api.proto +++ b/crates/cestory/api/proto/podr2-api.proto @@ -16,6 +16,7 @@ message EchoMessage { service Podr2VerifierApi { rpc request_batch_verify(RequestBatchVerify) returns (ResponseBatchVerify) {} + rpc request_aggregate_signature(RequestAggregateSignature) returns (ResponseAggregateSignature) {} } message Tag { @@ -54,12 +55,12 @@ message GenTagMsg { bytes u_sig = 2; bytes signature = 3; } - -message RequestBatchVerify { - message Qslice { +message Qslice { repeated uint32 random_index_list = 1; repeated bytes random_list = 2; - } +} + +message RequestBatchVerify { message BatchVerifyParam { repeated string names = 1; repeated string us = 2; @@ -70,6 +71,7 @@ message RequestBatchVerify { Qslice qslices = 2; repeated bytes u_sigs = 3; bytes miner_id = 4; + repeated uint64 service_bloom_filter = 5; } message ResponseBatchVerify { @@ -79,6 +81,26 @@ message ResponseBatchVerify { bytes signature = 4; } + +message RequestAggregateSignature { + message VerifyInServiceFileStructure { + bytes miner_id = 1; + bool result =2; + string sigma = 3; + repeated uint64 service_bloom_filter = 4; + bytes signature = 5; + } + repeated VerifyInServiceFileStructure verify_inservice_file_history = 1; + Qslice qslices = 2; +} + +message ResponseAggregateSignature { + bytes tee_account_id = 1; + bytes signature = 2; +} + + + enum StatusCode { Success = 0; Processing = 1; diff --git a/crates/cestory/src/light_validation/justification.rs b/crates/cestory/src/light_validation/justification.rs index e334efab..344bfa99 100644 --- a/crates/cestory/src/light_validation/justification.rs +++ b/crates/cestory/src/light_validation/justification.rs @@ -71,13 +71,13 @@ impl GrandpaJustification { NumberFor: finality_grandpa::BlockNumberOps, { let mut justification = GrandpaJustification::::decode(&mut &*encoded).map_err(|e| { - log::error!( - "decode justification error:{:?}, block:{:?}, input(len:{}):{}", - e, - finalized_target.1, - encoded.len(), - hex::encode(encoded) - ); + // log::error!( + // "decode justification error:{:?}, block:{:?}, input(len:{}):{}", + // e, + // finalized_target.1, + // encoded.len(), + // hex::encode(encoded) + // ); ClientError::JustificationDecode })?; justification.grandpa_note_stalled = grandpa_note_stalled; diff --git a/crates/cestory/src/podr2.rs b/crates/cestory/src/podr2.rs index d0544b34..98d3ac6e 100644 --- a/crates/cestory/src/podr2.rs +++ b/crates/cestory/src/podr2.rs @@ -8,8 +8,8 @@ use ces_pdp::{HashSelf, Keys, QElement, Tag as PdpTag}; use cestory_api::podr2::{ podr2_api_server::{self, Podr2Api}, podr2_verifier_api_server::{self, Podr2VerifierApi}, - request_batch_verify::Qslice, - tag, EchoMessage, GenTagMsg, RequestBatchVerify, RequestGenTag, ResponseBatchVerify, ResponseGenTag, Tag as ApiTag, + tag, EchoMessage, GenTagMsg, Qslice, RequestAggregateSignature, RequestBatchVerify, RequestGenTag, + ResponseAggregateSignature, ResponseBatchVerify, ResponseGenTag, Tag as ApiTag, }; use cp_bloom_filter::{binary, BloomFilter}; use crypto::{digest::Digest, sha2::Sha256}; @@ -115,7 +115,7 @@ struct VerifyServiceResultInfo { pub service_bloom_filter: BloomFilter, } -#[derive(Encode)] +#[derive(Encode, Clone)] pub struct Challenge { pub random_index_list: BoundedVec>, pub random_list: BoundedVec<[u8; 20], ConstU32<1024>>, @@ -167,7 +167,7 @@ impl Podr2Api for Podr2Server { .send(Err(Status::internal(err.to_string()))) .await .expect("send failure of permit locking msg fail"); - return + return; }, }; match result { @@ -185,7 +185,7 @@ impl Podr2Api for Podr2Server { .await .expect("Sending GenTagMsg with processing true fail!"); stream_rec_times += 1; - continue + continue; }; if !v.fragment_data.is_empty() && stream_rec_times == 1 { match new_self.process_gen_tag_request(v).await { @@ -198,7 +198,7 @@ impl Podr2Api for Podr2Server { .await .expect("Sending GenTagMsg failure msg to miner fail!"), }; - break + break; }; resp_tx .send(Err(Status::invalid_argument( @@ -206,13 +206,13 @@ impl Podr2Api for Podr2Server { ))) .await .expect("Sending error msg when gen tag fail!"); - break + break; }, Err(err) => { if let Some(io_err) = match_for_io_error(&err) { if io_err.kind() == ErrorKind::BrokenPipe { info!("The connection to the miner is interrupted"); - break + break; } } @@ -238,6 +238,8 @@ impl Podr2Api for Podr2Server { #[tonic::async_trait] impl Podr2VerifierApi for Podr2VerifierServer { + /// By passing in the Bloom filter, you can verify it in batches, + /// And finally get the on-chain signature through the aggregation methods #[must_use] async fn request_batch_verify( &self, @@ -249,15 +251,18 @@ impl Podr2VerifierApi for Podr2VerifierServer { let agg_proof = if let Some(agg_proof) = request.agg_proof { agg_proof } else { - return Err(Status::invalid_argument("Lack of request parameter agg_proof")) + return Err(Status::invalid_argument("Lack of request parameter agg_proof")); }; let qslices = if let Some(qslices) = request.qslices { qslices } else { - return Err(Status::invalid_argument("Lack of request parameter qslices")) + return Err(Status::invalid_argument("Lack of request parameter qslices")); }; let q_elements = convert_to_q_elements(qslices.clone())?; - let mut service_bloom_filter = BloomFilter([0u64; 256]); + let mut service_bloom_filter: BloomFilter = request + .service_bloom_filter + .try_into() + .unwrap_or_else(|_| BloomFilter::default()); let miner_id: [u8; 32] = request .miner_id .clone() @@ -300,7 +305,9 @@ impl Podr2VerifierApi for Podr2VerifierServer { false }, }) { - return Err(Status::internal("The u_sig passed in is inconsistent with the u in the corresponding tag.")) + return Err(Status::internal( + "The u_sig passed in is inconsistent with the u in the corresponding tag.", + )); } result.batch_verify_result = self @@ -322,15 +329,26 @@ impl Podr2VerifierApi for Podr2VerifierServer { } let raw = VerifyServiceResultInfo { - miner_pbk: miner_id, + miner_pbk: miner_id.clone(), tee_account_id: self.ceseal_identity_key.into(), result: result.batch_verify_result, - sigma: agg_proof.sigma.into_bytes(), + sigma: agg_proof.sigma.clone().into_bytes(), chal: q_elements.1, service_bloom_filter: service_bloom_filter.clone(), }; + info!( + "[Batch verify]miner id is :{:?}miner_pbk:{:?}", + crate::pois::get_ss58_address(&miner_id.clone().to_raw_vec()).unwrap(), + hex::encode(miner_id.to_raw_vec()) + ); + info!("[Batch verify]tee_account_id:{:?}", hex::encode(self.ceseal_identity_key.clone())); + info!("[Batch verify]raw.result:{}", raw.result); + info!("[Batch verify]raw.sigma:{:?}", hex::encode(raw.sigma.clone())); + info!("[Batch verify]service_bloom_filter:{:?}", raw.service_bloom_filter.0); + //using podr2 keypair sign let podr2_sign = self.master_key.sign_data(&calculate_hash(&raw.encode())).0.to_vec(); + info!("[Batch verify]podr2_sign:{:?}", hex::encode(podr2_sign.clone())); result.tee_account_id = self.ceseal_identity_key.to_vec(); result.service_bloom_filter = service_bloom_filter.0.to_vec(); @@ -338,6 +356,108 @@ impl Podr2VerifierApi for Podr2VerifierServer { info!("[Batch verify] Batch Verify Completed in: {:.2?}.", now.elapsed()); Ok(Response::new(result)) } + + #[must_use] + async fn request_aggregate_signature( + &self, + request: tonic::Request, + ) -> Podr2Result { + let request = request.into_inner(); + let qslices = if let Some(qslices) = request.qslices { + qslices + } else { + return Err(Status::invalid_argument("Lack of request parameter qslices")); + }; + let q_elements = convert_to_q_elements(qslices.clone())?; + + let mut sigma = "".to_string(); + + let mut miner_id = [0u8; 32]; + + let tee_account_id: [u8; 32] = self.ceseal_identity_key.clone(); + + // Important:Miners need to submit 'verify_inservice_file_history' in the order of verification during request 'request_batch_verify'api! + let verify_inservice_file_structure_list = request.verify_inservice_file_history; + + //The last Bloom filter must be the most complete + let service_bloom_filter: BloomFilter = verify_inservice_file_structure_list + [verify_inservice_file_structure_list.len() - 1] + .service_bloom_filter + .clone() + .try_into() + .unwrap(); + + for el in verify_inservice_file_structure_list { + miner_id = el.miner_id.clone().try_into().map_err(|_| { + Status::invalid_argument(format!("the miner id {:?} is length is incorrect", &el.miner_id)) + })?; + + let raw = VerifyServiceResultInfo { + miner_pbk: miner_id.into(), + tee_account_id: tee_account_id.into(), + result: el.result, + sigma: el.sigma.clone().into_bytes(), + chal: q_elements.1.clone(), + service_bloom_filter: el.service_bloom_filter.clone().try_into().unwrap(), + }; + info!( + "-----------------------------miner id is :{:?}miner_pbk:{:?}", + crate::pois::get_ss58_address(&miner_id.clone().to_vec()).unwrap(), + hex::encode(miner_id.to_vec()) + ); + info!("-----------------------------tee_account_id:{:?}", hex::encode(self.ceseal_identity_key.clone())); + info!("-----------------------------raw.result:{:?}", raw.result); + info!("-----------------------------raw.sigma:{:?}", hex::encode(raw.sigma.clone())); + info!("-----------------------------service_bloom_filter:{:?}", raw.service_bloom_filter.clone()); + info!("-----------------------------encode value:{:?}", hex::encode(&raw.encode())); + info!("-----------------------------encode value hash:{:?}", hex::encode(&calculate_hash(&raw.encode()))); + + if !self.master_key.verify_data( + &sr25519::Signature::from_raw( + el.signature + .try_into() + .map_err(|_| Status::invalid_argument("The signature format is not correct".to_string()))?, + ), + &calculate_hash(&raw.encode()), + ) { + return Err(Status::invalid_argument("Verify service result signature fail!")); + }; + + sigma = self + .podr2_keys + .aggr_append_proof(sigma.clone(), el.sigma.clone()) + .map_err(|_| { + Status::invalid_argument(format!( + "Error when calculating aggregate proof accumulation,sigma is :{:?},sub sigma is :{:?}", + &sigma, &el.sigma + )) + })?; + } + + info!( + "[aggregate verify]miner id is :{:?}miner_pbk:{:?}", + crate::pois::get_ss58_address(&miner_id.clone().to_vec()).unwrap(), + hex::encode(miner_id.to_vec()) + ); + info!("[aggregate verify]tee_account_id:{:?}", hex::encode(self.ceseal_identity_key.clone())); + info!("[aggregate verify]agg_proof.sigma:{:?}", hex::encode(sigma.clone().into_bytes())); + info!("[aggregate verify]service_bloom_filter:{:?}", service_bloom_filter.0); + + let raw = VerifyServiceResultInfo { + miner_pbk: miner_id.into(), + tee_account_id: tee_account_id.into(), + result: true, + sigma: sigma.into_bytes(), + chal: q_elements.1, + service_bloom_filter, + }; + let podr2_sign = self.master_key.sign_data(&calculate_hash(&raw.encode())).0.to_vec(); + + let result = + ResponseAggregateSignature { tee_account_id: self.ceseal_identity_key.to_vec(), signature: podr2_sign }; + + Ok(Response::new(result)) + } } pub fn calculate_hash(input: &[u8]) -> Vec { @@ -400,7 +520,7 @@ impl Podr2Server { return Err(Status::invalid_argument(format!( "fragment: {:?} hash is :{:?}", &request.fragment_name, &fragment_data_hash_string - ))) + ))); } let mut tag_sig_info_history = TagSigInfo { @@ -434,7 +554,7 @@ impl Podr2Server { })?), &calculate_hash(&tag_sig_info_history.encode()), ) { - return Err(Status::invalid_argument("The last_tee_signature you provided is incorrect".to_string())) + return Err(Status::invalid_argument("The last_tee_signature you provided is incorrect".to_string())); }; }; @@ -489,12 +609,12 @@ fn match_for_io_error(err_status: &Status) -> Option<&std::io::Error> { let mut err: &(dyn Error + 'static) = err_status; loop { if let Some(io_err) = err.downcast_ref::() { - return Some(io_err) + return Some(io_err); } if let Some(h2_err) = err.downcast_ref::() { if let Some(io_err) = h2_err.get_io() { - return Some(io_err) + return Some(io_err); } } diff --git a/crates/cestory/src/podr2/proxy.rs b/crates/cestory/src/podr2/proxy.rs index 31f7d1f0..7f8066a1 100644 --- a/crates/cestory/src/podr2/proxy.rs +++ b/crates/cestory/src/podr2/proxy.rs @@ -3,8 +3,8 @@ use std::pin::Pin; use super::Podr2Result; use crate::expert::{CesealExpertStub, ExternalResourceKind}; use cestory_api::podr2::{ - podr2_api_server::Podr2Api, podr2_verifier_api_server::Podr2VerifierApi, EchoMessage, RequestBatchVerify, - RequestGenTag, ResponseBatchVerify, ResponseGenTag, + podr2_api_server::Podr2Api, podr2_verifier_api_server::Podr2VerifierApi, EchoMessage, RequestAggregateSignature, + RequestBatchVerify, RequestGenTag, ResponseAggregateSignature, ResponseBatchVerify, ResponseGenTag, }; use tokio_stream::Stream; use tonic::{Request, Response, Status, Streaming}; @@ -61,4 +61,10 @@ where .await?; self.inner.request_batch_verify(request).await } + async fn request_aggregate_signature( + &self, + request: Request, + ) -> Podr2Result { + self.inner.request_aggregate_signature(request).await + } } diff --git a/crates/cestory/src/pois.rs b/crates/cestory/src/pois.rs index 6b206043..3f21f010 100644 --- a/crates/cestory/src/pois.rs +++ b/crates/cestory/src/pois.rs @@ -993,9 +993,9 @@ use sp_core::crypto::{Ss58AddressFormat, Ss58AddressFormatRegistry, Ss58Codec}; #[derive(thiserror::Error, Debug)] #[error("{0}")] -struct AccountConvertError(String); +pub struct AccountConvertError(String); -fn get_ss58_address(account: &[u8]) -> std::result::Result { +pub fn get_ss58_address(account: &[u8]) -> std::result::Result { if account.len() != 32 { return Err(AccountConvertError("The length of raw account bytes must be 32".to_string())) }