Skip to content

Commit

Permalink
fix: use new gadget-sdk, remove code, use new network wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
tbraun96 committed Dec 2, 2024
1 parent dcfe35d commit e40259a
Show file tree
Hide file tree
Showing 8 changed files with 1,127 additions and 666 deletions.
1,384 changes: 1,055 additions & 329 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ async-trait = "0.1"
color-eyre = "0.6"
structopt = "0.3.26"
hex = "0.4"
k256 = { version = "0.13.4" }
tokio = { version = "^1", default-features = false, features = ["full", "rt-multi-thread"] }
tokio-stream = { version = "0.1", default-features = false }
tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter"] }
Expand All @@ -57,7 +58,7 @@ round-based = { version = "0.3.0", default-features = false, features = ["derive


[dependencies.gadget-sdk]
version = "0.4"
version = "0.6.0"
default-features = false
features = ["getrandom"]

Expand All @@ -72,8 +73,8 @@ round-based = { version = "0.3.0", default-features = false, features = ["derive
proptest = { version = "1.5.0", default-features = false, features = ["std", "bit-set", "fork", "timeout"] }
test-strategy = { version = "0.4.0", default-features = false }

cargo-tangle = "0.2"
blueprint-test-utils = { version = "0.1", default-features = false, features = ["std"] }
cargo-tangle = "0.3.1"
blueprint-test-utils = { version = "0.2.0", default-features = false, features = ["std"] }

alloy-primitives = "0.7.2"
alloy-provider = { version = "0.1", default-features = false, features = ["reqwest", "ws"] }
Expand All @@ -86,7 +87,7 @@ alloy-sol-types = "0.7.2"
alloy-contract = { version = "0.1" }

[build-dependencies]
blueprint-metadata = "0.1.6"
blueprint-metadata = "0.2.0"

[features]
default = ["std", "kv-sled"]
Expand Down
41 changes: 25 additions & 16 deletions src/keygen.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::collections::BTreeMap;

use crate::rounds::keygen as keygen_protocol;
use crate::FrostContext;
use api::services::events::JobCalled;
use frost_core::keys::{KeyPackage, PublicKeyPackage};
use frost_core::{Ciphersuite, VerifyingKey};
use gadget_sdk::contexts::MPCContext;
use gadget_sdk::futures::TryFutureExt;
use gadget_sdk::network::Network;
use gadget_sdk::network::round_based_compat::NetworkDeliveryWrapper;
use gadget_sdk::subxt_core::ext::sp_core::{ecdsa, Pair};
use gadget_sdk::subxt_core::utils::AccountId32;
use gadget_sdk::{self as sdk, random};
Expand All @@ -14,9 +17,6 @@ use sdk::event_listener::tangle::{
};
use sdk::tangle_subxt::tangle_testnet_runtime::api;

use crate::rounds::{delivery, keygen as keygen_protocol};
use crate::FrostContext;

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Unknown ciphersuite: {0}")]
Expand Down Expand Up @@ -92,30 +92,31 @@ pub async fn keygen(
.map_err(Error::Other)
.await?;
let my_ecdsa = context.config.first_ecdsa_signer()?;

let current_call_id = context.current_call_id().map_err(Error::Other).await?;
let net = context.keygen_network_backend(current_call_id);

let rng = random::rand::rngs::OsRng;
let kv = context.store();
let kv = context.store.clone();
let key = match ciphersuite.as_str() {
frost_ed25519::Ed25519Sha512::ID => keygen_internal::<frost_ed25519::Ed25519Sha512, _, _>(
frost_ed25519::Ed25519Sha512::ID => keygen_internal::<frost_ed25519::Ed25519Sha512, _>(
rng,
net,
kv,
my_ecdsa.signer().public(),
operators,
threshold,
current_call_id,
&context,
)
.await?
.serialize()?,
frost_secp256k1::Secp256K1Sha256::ID => {
keygen_internal::<frost_secp256k1::Secp256K1Sha256, _, _>(
keygen_internal::<frost_secp256k1::Secp256K1Sha256, _>(
rng,
net,
kv,
my_ecdsa.signer().public(),
operators,
threshold,
current_call_id,
&context,
)
.await?
.serialize()?
Expand All @@ -135,22 +136,22 @@ pub struct KeygenEntry<C: Ciphersuite> {
}

/// A genaric keygen protocol over any ciphersuite.
#[tracing::instrument(skip(rng, net, kv), fields(ciphersuite = %C::ID, i = tracing::field::Empty, n = %participants.len()))]
async fn keygen_internal<C, R, N>(
#[tracing::instrument(skip(rng, kv, context), fields(ciphersuite = %C::ID, i = tracing::field::Empty, n = %participants.len()))]
async fn keygen_internal<C, R>(
mut rng: R,
net: N,
kv: crate::kv::SharedDynKVStore<String, Vec<u8>>,
me: ecdsa::Public,
participants: BTreeMap<AccountId32, ecdsa::Public>,
t: u16,
call_id: u64,
context: &FrostContext,
) -> Result<VerifyingKey<C>, Error>
where
C: Ciphersuite + Send + Unpin,
<<C as Ciphersuite>::Group as frost_core::Group>::Element: Send + Unpin,
<<<C as Ciphersuite>::Group as frost_core::Group>::Field as frost_core::Field>::Scalar:
Send + Unpin,
R: random::RngCore + random::CryptoRng,
N: Network + Unpin,
{
let n = participants.len();
let i = participants
Expand All @@ -167,7 +168,15 @@ where
.enumerate()
.map(|(j, (_, ecdsa))| (j as u16, ecdsa))
.collect();
let delivery = delivery::NetworkDeliveryWrapper::new(net, i, parties);

let keygen_task_hash = gadget_sdk::compute_sha256_hash!(call_id.to_be_bytes(), "frost-keygen");

let delivery = NetworkDeliveryWrapper::new(
context.network_backend.clone(),
i as _,
keygen_task_hash,
parties.clone(),
);
let party = round_based::MpcParty::connected(delivery);
let (key_package, public_key_package) =
keygen_protocol::run::<R, C, _>(&mut rng, t, n, i, party, None).await?;
Expand Down
2 changes: 2 additions & 0 deletions src/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ pub trait KVStore {

fn get(&self, key: &Self::Key) -> Result<Option<Self::Value>, Self::Error>;
fn set(&self, key: Self::Key, value: Self::Value) -> Result<(), Self::Error>;
#[allow(dead_code)]
fn del(&self, key: &Self::Key) -> Result<(), Self::Error>;
#[allow(dead_code)]
fn ex(&self, key: &Self::Key) -> Result<bool, Self::Error>;
}

Expand Down
95 changes: 11 additions & 84 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
//! FROST Blueprint

use std::collections::BTreeMap;
use std::sync::Arc;

use color_eyre::eyre;
use gadget_sdk as sdk;
use gadget_sdk::network::{NetworkMultiplexer, StreamKey};
use gadget_sdk::subxt_core::ext::sp_core::{ecdsa, keccak_256};
use gadget_sdk::subxt_core::utils::AccountId32;
use gadget_sdk::contexts::MPCContext;
use gadget_sdk::keystore::TanglePairSigner;
use gadget_sdk::network::NetworkMultiplexer;
use gadget_sdk::subxt_core::ext::sp_core::ecdsa;

use kv::SharedDynKVStore;
use sdk::ctx::{KeystoreContext, ServicesContext, TangleClientContext};
use sdk::tangle_subxt::tangle_testnet_runtime::api;
use gadget_sdk::subxt::tx::Signer;
use sdk::contexts::{KeystoreContext, ServicesContext, TangleClientContext};

/// FROST Keygen module
pub mod keygen;
Expand All @@ -27,7 +25,7 @@ const NETWORK_PROTOCOL: &str = "/zcash/frost/1.0.0";

/// FROST Service Context that holds all the necessary context for the service
/// to run
#[derive(Clone, KeystoreContext, TangleClientContext, ServicesContext)]
#[derive(Clone, KeystoreContext, TangleClientContext, ServicesContext, MPCContext)]
pub struct FrostContext {
/// The overreaching configuration for the service
#[config]
Expand All @@ -36,6 +34,9 @@ pub struct FrostContext {
network_backend: Arc<NetworkMultiplexer>,
/// The key-value store for the service
store: kv::SharedDynKVStore<String, Vec<u8>>,
/// Account id
#[allow(dead_code)]
account_id: TanglePairSigner<ecdsa::Pair>,
}

impl FrostContext {
Expand Down Expand Up @@ -64,82 +65,8 @@ impl FrostContext {
None => Arc::new(kv::SledKVStore::in_memory()?),
},
config,
account_id: my_ecdsa_key,
network_backend: Arc::new(NetworkMultiplexer::new(gossip_handle)),
})
}

/// Get the key-value store
pub fn store(&self) -> SharedDynKVStore<String, Vec<u8>> {
self.store.clone()
}

/// Get the configuration
pub fn config(&self) -> &sdk::config::StdGadgetConfiguration {
&self.config
}

/// Get the network protocol
pub fn network_protocol(&self) -> &str {
NETWORK_PROTOCOL
}

/// Get the current blueprint id
pub fn blueprint_id(&self) -> eyre::Result<u64> {
self.config()
.protocol_specific
.tangle()
.map(|c| c.blueprint_id)
.map_err(|e| eyre::eyre!("Failed to get blueprint id: {e}"))
}

/// Get Current Service Operators' ECDSA Keys as a map.
pub async fn current_service_operators_ecdsa_keys(
&self,
) -> eyre::Result<BTreeMap<AccountId32, ecdsa::Public>> {
let client = self.tangle_client().await?;
let current_blueprint = self.blueprint_id()?;
let current_service_op = self.current_service_operators(&client).await?;
let storage = client.storage().at_latest().await?;
let mut map = BTreeMap::new();
for (operator, _) in current_service_op {
let addr = api::storage()
.services()
.operators(current_blueprint, &operator);
let maybe_pref = storage.fetch(&addr).await?;
if let Some(pref) = maybe_pref {
map.insert(operator, ecdsa::Public(pref.key));
} else {
return Err(eyre::eyre!(
"Failed to get operator's {operator} public ecdsa key"
));
}
}

Ok(map)
}

/// Get the current call id for this job.
pub async fn current_call_id(&self) -> Result<u64, eyre::Error> {
let client = self.tangle_client().await?;
let addr = api::storage().services().next_job_call_id();
let storage = client.storage().at_latest().await?;
let maybe_call_id = storage.fetch_or_default(&addr).await?;
Ok(maybe_call_id.saturating_sub(1))
}

/// Get the network backend for keygen job
pub fn keygen_network_backend(&self, call_id: u64) -> impl sdk::network::Network {
self.network_backend.multiplex(StreamKey {
task_hash: keccak_256(&[&b"keygen"[..], &call_id.to_le_bytes()[..]].concat()),
round_id: -1,
})
}

/// Get the network backend for signing job
pub fn signing_network_backend(&self, call_id: u64) -> impl sdk::network::Network {
self.network_backend.multiplex(StreamKey {
task_hash: keccak_256(&[&b"signing"[..], &call_id.to_le_bytes()[..]].concat()),
round_id: -1,
})
}
}
Loading

0 comments on commit e40259a

Please sign in to comment.