Skip to content

Commit

Permalink
Merge pull request #306 from CESSProject/feat/pubkeys_service
Browse files Browse the repository at this point in the history
feat:add get public service for miner to ensure which ceseal connect with
  • Loading branch information
0xbillw authored Feb 6, 2024
2 parents 2333c22 + fe94b97 commit 56f4aa9
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 27 deletions.
9 changes: 3 additions & 6 deletions crates/ces-pdp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,14 @@ pub fn gen_keypair(bits: usize) -> Keys {
// ).unwrap()).unwrap();
let skey = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
let pkey = RsaPublicKey::from(&skey);
println!("{:?}", hex::encode(pkey.to_pkcs1_der().unwrap().to_vec()));
println!("Podr2 public key is {:?}", hex::encode(pkey.to_pkcs1_der().unwrap().to_vec()));

Keys { skey, pkey }
}

pub fn gen_keypair_from_private_key(skey: RsaPrivateKey) -> Keys {
let pkey = skey.to_public_key();
Keys{
skey,
pkey,
}
Keys { skey, pkey }
}

use rsa::{
Expand All @@ -169,7 +166,7 @@ impl Keys {
.sign(Pkcs1v15Sign::new_raw(), data)
.map_err(|e| PDPError { error_code: FailCode::ParameterError(e.to_string()) })
}

pub fn verify_data(&self, hashed: &[u8], sig: &[u8]) -> Result<(), PDPError> {
self.pkey
.verify(Pkcs1v15Sign::new_raw(), hashed, sig)
Expand Down
1 change: 1 addition & 0 deletions crates/cestory/api/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ fn main() {

tonic_build::compile_protos("proto/pois-api.proto").unwrap();
tonic_build::compile_protos("proto/podr2-api.proto").unwrap();
tonic_build::compile_protos("proto/pubkeys.proto").unwrap();
}
45 changes: 45 additions & 0 deletions crates/cestory/api/proto/pubkeys.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
syntax = "proto3";

package ceseal.pubkeys;

// Provide the storage miners with Ceseal's various public key queries
service CesealPubkeysProvider {
// Get the Ceseal identity public key
rpc get_identity_pubkey(Request) returns (IdentityPubkeyResponse) {}
// Get the master public key
rpc get_master_pubkey(Request) returns (MasterPubkeyResponse) {}
// Get the PORD2 public key
rpc get_podr2_pubkey(Request) returns (Podr2PubkeyResponse) {}
}

message Request {
// The account id that the storage miner registered on the chain
bytes storage_miner_account_id = 1;
}

message IdentityPubkeyResponse {
// the identity public key
bytes pubkey = 1;
// The timestamp for the processing of the request
int64 timestamp = 2;
// Use the sr25519 algorithm to sign the timestamp fields above (use it's Big-Endian bytes)
bytes signature = 3;
}

message MasterPubkeyResponse {
// the master public key
bytes pubkey = 1;
// The timestamp for the processing of the request
int64 timestamp = 2;
// Use the sr25519 algorithm to sign the timestamp fields above (use it's Big-Endian bytes)
bytes signature = 3;
}

message Podr2PubkeyResponse {
// the PODR2 public key
bytes pubkey = 1;
// The timestamp for the processing of the request
int64 timestamp = 2;
// Use the RSA algorithm to sign the timestamp fields above (use it's Big-Endian bytes)
bytes signature = 3;
}
4 changes: 4 additions & 0 deletions crates/cestory/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ pub mod pois {
pub mod podr2 {
tonic::include_proto!("podr2");
}

pub mod pubkeys {
tonic::include_proto!("ceseal.pubkeys");
}
7 changes: 7 additions & 0 deletions crates/cestory/src/expert.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::types::MasterKey;

use super::{
pal::Platform, system::WorkerIdentityKey, types::ThreadPoolSafeBox, CesealProperties, CesealSafeBox, ChainStorage,
};
Expand Down Expand Up @@ -99,6 +101,10 @@ impl CesealExpertStub {
self.ceseal_props.identity_key.public()
}

pub fn master_key(&self) -> &MasterKey {
&self.ceseal_props.master_key
}

pub fn podr2_key(&self) -> &ces_pdp::Keys {
&self.ceseal_props.podr2_key
}
Expand Down Expand Up @@ -180,6 +186,7 @@ mod test {
let ceseal_props = CesealProperties {
role: WorkerRole::Full,
podr2_key: any_podr2_key(),
master_key: new_sr25519_key(),
identity_key: any_identity_key(),
cores: 2,
};
Expand Down
11 changes: 7 additions & 4 deletions crates/cestory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub mod expert;
mod light_validation;
pub mod podr2;
pub mod pois;
mod pubkeys;
mod secret_channel;
mod storage;
mod system;
Expand Down Expand Up @@ -833,7 +834,7 @@ async fn run_external_server<Platform>(
//FIXME: SHOULD BE DISABLE LOG KEY ON PRODUCTION !!!
debug!(
"Successfully load podr2 key public key is: {:?}",
&ceseal_props.podr2_key.pkey.to_pkcs1_der().unwrap().as_bytes()
hex::encode(&ceseal_props.podr2_key.pkey.to_pkcs1_der().unwrap().as_bytes())
);

let (ceseal_expert, expert_cmd_rx) = expert::CesealExpertStub::new(ceseal_props.clone());
Expand Down Expand Up @@ -862,9 +863,10 @@ async fn run_external_server<Platform>(
let pois_srv = pois::new_pois_certifier_api_server(pois_param.clone(), ceseal_expert.clone())
.max_decoding_message_size(MAX_DECODED_MSG_SIZE)
.max_encoding_message_size(MAX_ENCODED_MSG_SIZE);
let poisv_srv = pois::new_pois_verifier_api_server(pois_param, ceseal_expert)
let poisv_srv = pois::new_pois_verifier_api_server(pois_param, ceseal_expert.clone())
.max_decoding_message_size(MAX_DECODED_MSG_SIZE)
.max_encoding_message_size(MAX_ENCODED_MSG_SIZE);
let pubkeys = pubkeys::new_pubkeys_provider_server(ceseal_expert);

info!(
"keyfairy ready, external server will listening on {} run with {:?} role",
Expand All @@ -873,12 +875,13 @@ async fn run_external_server<Platform>(
let mut server = Server::builder();
let router = match ceseal_props.role {
ces_types::WorkerRole::Full => server
.add_service(pubkeys)
.add_service(podr2_srv)
.add_service(podr2v_srv)
.add_service(pois_srv)
.add_service(poisv_srv),
ces_types::WorkerRole::Verifier => server.add_service(podr2v_srv).add_service(poisv_srv),
ces_types::WorkerRole::Marker => server.add_service(podr2_srv).add_service(pois_srv),
ces_types::WorkerRole::Verifier => server.add_service(pubkeys).add_service(podr2v_srv).add_service(poisv_srv),
ces_types::WorkerRole::Marker => server.add_service(pubkeys).add_service(podr2_srv).add_service(pois_srv),
};
let result = router.serve(public_listener_addr).await;
let _ = ext_srv_quit_tx.send(result);
Expand Down
63 changes: 49 additions & 14 deletions crates/cestory/src/podr2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{expert::CesealExpertStub, types::ThreadPoolSafeBox};
use crate::{
expert::{CesealExpertStub, ExternalResourceKind},
types::ThreadPoolSafeBox,
};
use anyhow::{anyhow, Result};
use ces_crypto::sr25519::Signing;
use ces_pdp::{HashSelf, Keys, QElement, Tag as PdpTag};
Expand Down Expand Up @@ -38,6 +41,7 @@ pub fn new_podr2_api_server(ceseal_expert: CesealExpertStub) -> Podr2ApiServer {
threadpool: ceseal_expert.thread_pool(),
block_num: 1024,
ceseal_identity_key: ceseal_expert.identify_public_key().0,
ceseal_expert: ceseal_expert.clone(),
},
ceseal_expert,
};
Expand Down Expand Up @@ -66,6 +70,7 @@ pub struct Podr2Server {
pub threadpool: ThreadPoolSafeBox,
pub block_num: u64,
pub ceseal_identity_key: [u8; 32],
pub ceseal_expert: CesealExpertStub,
}

pub struct Podr2VerifierServer {
Expand Down Expand Up @@ -144,10 +149,25 @@ impl Podr2Api for Podr2Server {
threadpool: self.threadpool.clone(),
block_num: self.block_num.clone(),
ceseal_identity_key: self.ceseal_identity_key.clone(),
ceseal_expert: self.ceseal_expert.clone(),
};
//start receive
tokio::spawn(async move {
while let Some(result) = in_stream.next().await {
let _permit = match new_self
.ceseal_expert
.try_acquire_permit(ExternalResourceKind::Pord2Service)
.await
{
Ok(p) => p,
Err(err) => {
resp_tx
.send(Err(Status::internal(err.to_string())))
.await
.expect("send failure of permit locking msg fail");
return
},
};
match result {
Ok(v) => {
if v.fragment_data.is_empty() && stream_rec_times == 0 {
Expand All @@ -166,7 +186,7 @@ impl Podr2Api for Podr2Server {
continue
};
if !v.fragment_data.is_empty() && stream_rec_times == 1 {
match new_self.process_gen_tag_request(v) {
match new_self.process_gen_tag_request(v).await {
Ok(response) => resp_tx
.send(Ok(response))
.await
Expand Down Expand Up @@ -354,7 +374,7 @@ fn convert_to_q_elements(qslices: Qslice) -> Result<(Vec<QElement>, Challenge),
}

impl Podr2Server {
fn process_gen_tag_request<'life0>(&'life0 self, request: RequestGenTag) -> Result<ResponseGenTag, Status> {
async fn process_gen_tag_request<'life0>(&'life0 self, request: RequestGenTag) -> Result<ResponseGenTag, Status> {
let now = Instant::now();
let mut h = Podr2Hash::new();
h.load_field(request.custom_data.as_bytes());
Expand All @@ -369,10 +389,6 @@ impl Podr2Server {
.try_into()
.map_err(|_| Status::invalid_argument("file_name hash bytes length should be 64".to_string()))?;

let pool = self
.threadpool
.lock()
.map_err(|e| Status::internal("lock global threadpool fail:".to_string() + &e.to_string()))?;
//check fragement data is equal to fragement name
let mut check_fragment_hash = Podr2Hash::new();
check_fragment_hash.load_field(&request.fragment_data);
Expand All @@ -384,13 +400,6 @@ impl Podr2Server {
&request.fragment_name, &fragment_data_hash_string
)))
}
let tag = self
.podr2_keys
.sig_gen_with_data(request.fragment_data, self.block_num, &request.fragment_name, h, pool.clone())
.map_err(|e| Status::internal(format!("AlgorithmError: {}", e.error_code.to_string())))?;
let u_sig = self.podr2_keys.sign_data(&calculate_hash(tag.t.u.as_bytes())).map_err(|e| {
Status::invalid_argument(format!("Failed to calculate u's signature {:?}", e.error_code.to_string()))
})?;

let mut tag_sig_info_history = TagSigInfo {
miner: AccountId32::from_slice(&request.miner_id[..])
Expand Down Expand Up @@ -440,6 +449,32 @@ impl Podr2Server {
.sign_data(&calculate_hash(&tag_sig_info_history.encode()))
.0
.to_vec();
let new_self = Podr2Server {
podr2_keys: self.podr2_keys.clone(),
master_key: self.master_key.clone(),
threadpool: self.threadpool.clone(),
block_num: self.block_num.clone(),
ceseal_identity_key: self.ceseal_identity_key.clone(),
ceseal_expert: self.ceseal_expert.clone(),
};
let tag = tokio::task::spawn_blocking(move || {
let pool = new_self
.threadpool
.lock()
.map_err(|e| Status::internal("lock global threadpool fail:".to_string() + &e.to_string()))?;
new_self
.podr2_keys
.sig_gen_with_data(request.fragment_data, new_self.block_num, &request.fragment_name, h, pool.clone())
.map_err(|_| Status::invalid_argument("Algorithm error".to_string()))
})
.await
.map_err(|_| Status::invalid_argument("Waiting for tag generate fail".to_string()))??;

//compute u signature
let u_sig = self.podr2_keys.sign_data(&calculate_hash(tag.t.u.as_bytes())).map_err(|e| {
Status::invalid_argument(format!("Failed to calculate u's signature {:?}", e.error_code.to_string()))
})?;

info!("[🚀Generate tag] PoDR2 Sig Gen Completed in: {:.2?}. file name is {:?}", now.elapsed(), &tag.t.name);
Ok(ResponseGenTag {
processing: true,
Expand Down
91 changes: 91 additions & 0 deletions crates/cestory/src/pubkeys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::expert::CesealExpertStub;
use cestory_api::pubkeys::{
ceseal_pubkeys_provider_server::{
CesealPubkeysProvider, CesealPubkeysProviderServer as CesealPubkeysProviderServerPb,
},
IdentityPubkeyResponse, MasterPubkeyResponse, Podr2PubkeyResponse, Request as InnerReq,
};
use sp_core::{crypto::AccountId32, ByteArray, Pair};
use std::result::Result as StdResult;
use tonic::{Request, Response, Status};

pub type Result<T> = StdResult<Response<T>, Status>;
pub type CesealPubkeysProviderServer = CesealPubkeysProviderServerPb<CesealPubkeysProviderImpl>;

pub struct CesealPubkeysProviderImpl {
ceseal_expert: CesealExpertStub,
}

pub fn new_pubkeys_provider_server(ceseal_expert: CesealExpertStub) -> CesealPubkeysProviderServer {
CesealPubkeysProviderServerPb::new(CesealPubkeysProviderImpl { ceseal_expert })
}

async fn is_storage_miner_registered_on_chain(
ceseal_expert: &CesealExpertStub,
account_id: &[u8],
) -> StdResult<(), Status> {
let account_id = AccountId32::from_slice(account_id).map_err(|_| Status::internal("invalid input account"))?;
let registered = ceseal_expert
.using_chain_storage(move |opt| {
if let Some(cs) = opt {
cs.is_storage_miner_registered_ignore_state(account_id)
} else {
false
}
})
.await
.map_err(|e| Status::internal(format!("internal error: {}", e.to_string())))?;
if !registered {
return Err(Status::internal("the storage miner is not registered on the chain"))
}
Ok(())
}

#[tonic::async_trait]
impl CesealPubkeysProvider for CesealPubkeysProviderImpl {
async fn get_identity_pubkey(&self, request: Request<InnerReq>) -> Result<IdentityPubkeyResponse> {
let request = request.into_inner();
is_storage_miner_registered_on_chain(&self.ceseal_expert, &request.storage_miner_account_id[..]).await?;
let now_ts = chrono::Utc::now().timestamp_millis();
let pubkey = self.ceseal_expert.identify_public_key();
let sign = self.ceseal_expert.identity_key().sign(&now_ts.to_be_bytes());
Ok(Response::new(IdentityPubkeyResponse {
pubkey: pubkey.to_raw_vec(),
timestamp: now_ts,
signature: sign.0.to_vec(),
}))
}

async fn get_master_pubkey(&self, request: Request<InnerReq>) -> Result<MasterPubkeyResponse> {
let request = request.into_inner();
is_storage_miner_registered_on_chain(&self.ceseal_expert, &request.storage_miner_account_id[..]).await?;
let now_ts = chrono::Utc::now().timestamp_millis();
let pubkey = self.ceseal_expert.master_key().public();
let sign = self.ceseal_expert.master_key().sign(&now_ts.to_be_bytes());
Ok(Response::new(MasterPubkeyResponse {
pubkey: pubkey.to_raw_vec(),
timestamp: now_ts,
signature: sign.0.to_vec(),
}))
}

async fn get_podr2_pubkey(&self, request: Request<InnerReq>) -> Result<Podr2PubkeyResponse> {
use rsa::{pkcs1::EncodeRsaPublicKey, Pkcs1v15Sign};

let request = request.into_inner();
is_storage_miner_registered_on_chain(&self.ceseal_expert, &request.storage_miner_account_id[..]).await?;
let now_ts = chrono::Utc::now().timestamp_millis();
let pubkey = self.ceseal_expert.podr2_key().pkey.clone();
let pubkey = pubkey
.to_pkcs1_der()
.map_err(|e| Status::internal(format!("PKCS#1-encoding Podr2 public key error: {:?}", e)))?
.to_vec();
let sign = self
.ceseal_expert
.podr2_key()
.skey
.sign(Pkcs1v15Sign::new_raw(), &now_ts.to_be_bytes())
.map_err(|e| Status::internal(format!("Podr2 key sign error: {:?}", e)))?;
Ok(Response::new(Podr2PubkeyResponse { pubkey, timestamp: now_ts, signature: sign }))
}
}
4 changes: 4 additions & 0 deletions crates/cestory/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ mod storage_ext {
self.execute_with(|| pallet_sminer::pallet::Pallet::miner_items(miner_account_id))
}

pub fn is_storage_miner_registered_ignore_state(&self, miner_account_id: AccountId) -> bool {
self.get_storage_miner_info(miner_account_id).is_some()
}

/// Return `None` if given ceseal hash is not allowed on-chain
pub(crate) fn get_ceseal_bin_added_at(&self, runtime_hash: &[u8]) -> Option<chain::BlockNumber> {
self.execute_with(|| pallet_tee_worker::CesealBinAddedAt::<chain::Runtime>::get(runtime_hash))
Expand Down
Loading

0 comments on commit 56f4aa9

Please sign in to comment.