Skip to content

Commit

Permalink
implement into ecdsa, identity handle, send job
Browse files Browse the repository at this point in the history
  • Loading branch information
rkdud007 committed Apr 26, 2024
1 parent d8c2419 commit 091f628
Show file tree
Hide file tree
Showing 19 changed files with 170 additions and 97 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ futures-util = "0.3.30"
hex = "0.4.3"
itertools = "0.12.1"
libp2p = { version = "0.53.2", features = [
"secp256k1",

"ecdsa",
"tokio",
"gossipsub",
"kad",
Expand All @@ -45,7 +46,6 @@ libp2p = { version = "0.53.2", features = [
"yamux",
"quic",
] }
libsecp256k1 = "0.7.1"
num-bigint = "0.4.4"
proptest = "1.4.0"
proptest-derive = "0.4.0"
Expand Down
3 changes: 1 addition & 2 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ cairo-felt.workspace = true
futures.workspace = true
hex.workspace = true
libp2p.workspace = true
libsecp256k1.workspace = true
num-bigint.workspace = true
proptest-derive.workspace = true
proptest.workspace = true
Expand All @@ -25,4 +24,4 @@ starknet.workspace = true
strum.workspace = true
tempfile.workspace = true
thiserror.workspace = true
tokio.workspace = true
tokio.workspace = true
35 changes: 30 additions & 5 deletions crates/common/src/fuzzing.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::job::{Job, JobData};

use proptest::{
arbitrary::{any, Arbitrary},
prop_compose,
strategy::{BoxedStrategy, Strategy},
};
use starknet::providers::sequencer::models::L1Address;

use crate::job::{Job, JobData};
use starknet_crypto::FieldElement;

// This generates a random Job object for testing purposes.
prop_compose! {
Expand All @@ -25,15 +26,15 @@ impl Arbitrary for Job {
fn arbitrary() -> Self::Strategy {
let abs_state = arb_state();
abs_state
.prop_map(|(reward, num_of_steps, cairo_pie_compressed, secret_key)| {
.prop_map(|(reward, num_of_steps, cairo_pie_compressed, _)| {
Job::from_job_data(
JobData {
reward,
num_of_steps,
cairo_pie_compressed,
registry_address: L1Address::random(),
registry_address: FieldElement::ZERO,
},
libsecp256k1::SecretKey::parse(&secret_key).unwrap(),
libp2p::identity::ecdsa::Keypair::generate(),
)
})
.boxed()
Expand All @@ -42,3 +43,27 @@ impl Arbitrary for Job {
Self::arbitrary()
}
}

#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;

proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
#[test]
fn job_verify_signature(job in any::<Job>()) {
assert!(job.verify_signature());
}
}

proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
#[test]
fn job_serialization(job in any::<Job>()) {
let serialized_job = serde_json::to_string(&job).unwrap();
let deserialized_job: Job = serde_json::from_str(&serialized_job).unwrap();
assert_eq!(job, deserialized_job)
}
}
}
35 changes: 35 additions & 0 deletions crates/common/src/identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use starknet::{core::types::FieldElement, signers::SigningKey};

pub struct IdentityHandler {
/// Key pair for the p2p network.
/// This represents the identity of the node in the network.
pub p2p_keypair: libp2p::identity::Keypair,
/// The signing key for the StarkNet network.
/// This is used to sign messages and transactions.
pub signing_key: SigningKey,
}

impl IdentityHandler {
pub fn new(private_key: FieldElement) -> Self {
let secret_key = libp2p::identity::ecdsa::SecretKey::try_from_bytes(
private_key.to_bytes_be().as_slice(),
)
.expect("Failed to create secret key from private key.");
let p2p_keypair =
libp2p::identity::Keypair::from(libp2p::identity::ecdsa::Keypair::from(secret_key));
let signing_key = SigningKey::from_secret_scalar(private_key);
Self { p2p_keypair, signing_key }
}

pub fn get_keypair(&self) -> libp2p::identity::Keypair {
self.p2p_keypair.clone()
}

pub fn get_ecdsa_keypair(&self) -> libp2p::identity::ecdsa::Keypair {
<libp2p::identity::Keypair as Clone>::clone(&self.p2p_keypair).try_into_ecdsa().unwrap()
}

pub fn get_signing_key(&self) -> SigningKey {
self.signing_key.clone()
}
}
60 changes: 32 additions & 28 deletions crates/common/src/job.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use crate::hash;
use libsecp256k1::{Message, PublicKey, SecretKey, Signature};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use starknet::core::types::FromByteSliceError;
use starknet::providers::sequencer::models::L1Address;
use starknet_crypto::{poseidon_hash_many, FieldElement};
use starknet_crypto::FieldElement;
use std::{
fmt::Display,
hash::{DefaultHasher, Hash, Hasher},
Expand All @@ -18,36 +15,27 @@ use std::{
Additionally, the object holds the signature and public key of the delegator, enabling the executor to prove to the Registry that the task was intended by the delegator.
The Job object also includes the target registry where the delegator expects this proof to be verified.
*/

#[serde_as]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Job {
pub job_data: JobData,
#[serde_as(as = "[_; 65]")]
pub public_key: [u8; 65], // The public key of the delegator, used in the bootloader stage to confirm authenticity of the Job<->Delegator relationship
#[serde_as(as = "[_; 64]")]
pub signature: [u8; 64], // The signature of the delegator, used in the bootloader stage to confirm authenticity of the Job<->Delegator relationship
pub public_key: Vec<u8>, // The public key of the delegator, used in the bootloader stage to confirm authenticity of the Job<->Delegator relationship
pub signature: Vec<u8>, // The signature of the delegator, used in the bootloader stage to confirm authenticity of the Job<->Delegator relationship
}

impl Job {
pub fn from_job_data(job_data: JobData, secret_key: SecretKey) -> Self {
let felts: Vec<FieldElement> = job_data.to_owned().try_into().unwrap();
let message = Message::parse(&poseidon_hash_many(&felts).to_bytes_be());
let (signature, _recovery) = libsecp256k1::sign(&message, &secret_key);

Self {
job_data,
public_key: PublicKey::from_secret_key(&secret_key).serialize(),
signature: signature.serialize(),
}
pub fn from_job_data(job_data: JobData, key_pair: libp2p::identity::ecdsa::Keypair) -> Self {
let message: Vec<u8> = job_data.to_owned().try_into().unwrap();
let public_key = key_pair.public();
let signature = key_pair.sign(&message);
Self { job_data, public_key: public_key.to_bytes(), signature }
}

pub fn verify_signature(&self) -> bool {
let felts: Vec<FieldElement> = self.job_data.to_owned().try_into().unwrap();
let message = Message::parse(&poseidon_hash_many(&felts).to_bytes_be());
let signature = Signature::parse_overflowing(&self.signature);
let pubkey = PublicKey::parse(&self.public_key).unwrap();
libsecp256k1::verify(&message, &signature, &pubkey)
let message: Vec<u8> = self.job_data.to_owned().try_into().unwrap();
let public_key =
libp2p::identity::ecdsa::PublicKey::try_from_bytes(self.public_key.as_slice()).unwrap();
let signature = &self.signature;
public_key.verify(&message, signature)
}
}

Expand All @@ -56,20 +44,36 @@ pub struct JobData {
pub reward: u32,
pub num_of_steps: u32,
pub cairo_pie_compressed: Vec<u8>,
pub registry_address: L1Address,
pub registry_address: FieldElement,
}

impl JobData {
pub fn new(
reward: u32,
num_of_steps: u32,
cairo_pie_compressed: Vec<u8>,
registry_address: L1Address,
registry_address: FieldElement,
) -> Self {
Self { reward, num_of_steps, cairo_pie_compressed, registry_address }
}
}

impl TryFrom<JobData> for Vec<u8> {
type Error = FromByteSliceError;
fn try_from(value: JobData) -> Result<Self, Self::Error> {
let mut felts: Vec<FieldElement> =
vec![FieldElement::from(value.reward), FieldElement::from(value.num_of_steps)];
felts.extend(
value
.cairo_pie_compressed
.chunks(31)
.map(|chunk| FieldElement::from_byte_slice_be(chunk).unwrap()),
);
felts.push(value.registry_address);
Ok(felts.iter().flat_map(|felt| felt.to_bytes_be()).collect())
}
}

impl TryFrom<JobData> for Vec<FieldElement> {
type Error = FromByteSliceError;
fn try_from(value: JobData) -> Result<Self, Self::Error> {
Expand All @@ -81,7 +85,7 @@ impl TryFrom<JobData> for Vec<FieldElement> {
.chunks(31)
.map(|chunk| FieldElement::from_byte_slice_be(chunk).unwrap()),
);
felts.push(FieldElement::from_byte_slice_be(&value.registry_address.to_fixed_bytes())?);
felts.push(value.registry_address);
Ok(felts)
}
}
Expand Down
4 changes: 1 addition & 3 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod hash_macro;
pub mod identity;
pub mod job;
pub mod job_trace;
pub mod job_witness;
Expand All @@ -9,6 +10,3 @@ pub mod topic;
pub mod vec252;

mod fuzzing;

#[cfg(test)]
pub mod tests;
20 changes: 0 additions & 20 deletions crates/common/src/tests/job.rs

This file was deleted.

1 change: 0 additions & 1 deletion crates/common/src/tests/mod.rs

This file was deleted.

2 changes: 1 addition & 1 deletion crates/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ cairo-proof-parser.workspace = true
futures.workspace = true
hex.workspace = true
itertools.workspace = true
libsecp256k1.workspace = true
libp2p.workspace = true
rand.workspace = true
serde_json.workspace = true
serde.workspace = true
Expand Down
14 changes: 7 additions & 7 deletions crates/compiler/src/cairo_compiler/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::{errors::CompilerControllerError, traits::CompilerController};
use async_process::Stdio;
use futures::Future;
use libsecp256k1::SecretKey;
use sharp_p2p_common::job::JobData;
use sharp_p2p_common::layout::Layout;
use sharp_p2p_common::{job::Job, process::Process};
use starknet::providers::sequencer::models::L1Address;
use starknet_crypto::FieldElement;
use std::path::PathBuf;
use std::{io::Read, pin::Pin};
use tempfile::NamedTempFile;
Expand All @@ -15,12 +14,13 @@ use tracing::debug;
pub mod tests;

pub struct CairoCompiler {
signing_key: SecretKey,
keypair: libp2p::identity::ecdsa::Keypair,
registry_contract: FieldElement,
}

impl CairoCompiler {
pub fn new(signing_key: SecretKey) -> Self {
Self { signing_key }
pub fn new(keypair: libp2p::identity::ecdsa::Keypair, registry_contract: FieldElement) -> Self {
Self { keypair, registry_contract }
}
}

Expand Down Expand Up @@ -108,9 +108,9 @@ impl CompilerController for CairoCompiler {
reward: 0, // TODO: calculate this properly
num_of_steps: 0, // TODO: calculate this properly
cairo_pie_compressed: cairo_pie_bytes,
registry_address: L1Address::random(),
registry_address: self.registry_contract,
},
self.signing_key,
self.keypair.clone(),
))
});

Expand Down
12 changes: 5 additions & 7 deletions crates/compiler/src/cairo_compiler/tests/single_job.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rand::thread_rng;
use starknet_crypto::FieldElement;

use crate::{
cairo_compiler::{tests::models::fixture, CairoCompiler},
Expand All @@ -7,19 +7,17 @@ use crate::{

#[tokio::test]
async fn run_single_job() {
let mut rng = thread_rng();
let fixture = fixture();

let compiler = CairoCompiler::new(libsecp256k1::SecretKey::random(&mut rng));
let compiler =
CairoCompiler::new(libp2p::identity::ecdsa::Keypair::generate(), FieldElement::ZERO);
compiler.run(fixture.program_path, fixture.program_input_path).unwrap().await.unwrap();
}

#[tokio::test]
async fn abort_single_jobs() {
let mut rng = thread_rng();
let fixture = fixture();

let compiler = CairoCompiler::new(libsecp256k1::SecretKey::random(&mut rng));
let compiler =
CairoCompiler::new(libp2p::identity::ecdsa::Keypair::generate(), FieldElement::ZERO);
let job = compiler.run(fixture.program_path, fixture.program_input_path).unwrap();
job.abort().await.unwrap();
job.await.unwrap_err();
Expand Down
4 changes: 3 additions & 1 deletion crates/delegator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ license-file.workspace = true
[dependencies]
futures-util.workspace = true
libp2p.workspace = true
libsecp256k1.workspace = true
sharp-p2p-common.workspace = true
sharp-p2p-peer.workspace = true
sharp-p2p-compiler.workspace = true
tokio.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
starknet.workspace = true
serde_json.workspace = true
Loading

0 comments on commit 091f628

Please sign in to comment.