sodot_mpc/schemes/mod.rs
1/// ECDSA threshold cryptography implementation.
2pub mod ecdsa;
3/// Ed25519 threshold cryptography implementation.
4pub mod ed25519;
5
6pub mod bip340;
7
8pub use bip340::Bip340;
9pub use ecdsa::Ecdsa;
10pub use ed25519::Ed25519;
11
12use crate::{
13 KeygenId, KeygenPrivateKey, Result, RoomUUID, SodotError,
14 ffi::{self, AsRawFFI, ConstStr, FromFFI, HeapString, async_ffi_single},
15};
16use std::{marker::PhantomData, num::NonZeroU16};
17
18/// The core trait for implementing cryptographic schemes using threshold signatures.
19///
20/// The `Scheme` trait provides the foundational functionality for multi-party computation
21/// protocols, including key generation initialization and room creation. Concrete
22/// implementations of this trait will provide specific cryptographic schemes like
23/// ECDSA, Ed25519, BIP340, and SR25519.
24///
25/// # Key Concepts
26///
27/// - **Threshold Cryptography**: Multiple parties collaborate to generate keys and sign messages
28/// - **MPC (Multi-Party Computation)**: Secure protocols that don't require a trusted dealer
29/// - **Rooms**: Communication channels that coordinate the MPC protocols between parties
30/// - **Host URL**: The Sodot relay server that facilitates communication between parties
31///
32/// # Basic Workflow
33///
34/// 1. Initialize the scheme with a host URL
35/// 2. Generate keygen initialization material using `init_keygen()`
36/// 3. Create a room using `create_room()`
37/// 4. Coordinate with other parties to perform MPC operations
38///
39/// This trait defines the common interface for all cryptographic schemes supported
40/// by the Sodot SDK. It provides methods for key generation initialization and
41/// room creation for multi-party computation operations.
42///
43pub(crate) trait Scheme {
44 /// Creates a new instance of the scheme with the specified host URL.
45 fn new(host_url: String) -> Self;
46
47 /// Returns the host URL configured for this scheme instance.
48 fn host_url(&self) -> &str;
49
50 /// Creates a new scheme instance using the default production host URL.
51 ///
52 /// Convenience method that creates an instance configured to use
53 /// the default Sodot production relay server at "us1.sodot.dev".
54 fn with_default_host() -> Self
55 where
56 Self: Sized,
57 {
58 Self::new("us1.sodot.dev".to_string())
59 }
60
61 /// Creates a new scheme instance using the test host URL.
62 ///
63 /// Only available in test builds and creates an instance configured
64 /// to use the Sodot test relay server.
65 #[cfg(test)]
66 fn with_test_host() -> Self
67 where
68 Self: Sized,
69 {
70 Self::new(crate::TEST_HOST_URL.to_string())
71 }
72
73 /// Initializes the key generation process by creating a keygen ID and private key.
74 ///
75 /// Generates the initial cryptographic material needed to participate in multi-party
76 /// key generation protocols. The keygen ID serves as a unique identifier for this party,
77 /// while the keygen private key is used for authentication.
78 fn init_keygen(&self) -> Result<(KeygenId, KeygenPrivateKey), SodotError> {
79 let mut keygen_id = HeapString::NULL;
80 let mut keygen_private_key = HeapString::NULL;
81
82 let result = unsafe { ffi::sodot_init_keygen(&mut keygen_id, &mut keygen_private_key) };
83
84 Result::from(result)?;
85
86 Ok((KeygenId::parse_ffi(keygen_id.as_str()), KeygenPrivateKey::parse_ffi(keygen_private_key.as_str())))
87 }
88
89 /// Creates a room for coordinating multi-party computation protocols.
90 ///
91 /// A room serves as a communication channel and session identifier for MPC operations.
92 /// All parties participating in the same protocol must use the same room UUID.
93 /// Typically, one party creates the room and shares the UUID with other participants.
94 fn create_room(&self, num_parties: NonZeroU16, api_key: &str) -> impl Future<Output = Result<RoomUUID, SodotError>> {
95 let host_url = ConstStr::from_str(self.host_url());
96 let api_key = ConstStr::from_str(api_key);
97
98 async_ffi_single(move |cb| unsafe {
99 ffi::sodot_create_room(host_url.raw_ffi(), num_parties.get(), api_key.raw_ffi(), cb.callback(), cb.extra())
100 })
101 }
102}
103
104/// A public key base type
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct PublicKey<T, const N: usize>(pub(crate) [u8; N], pub(crate) PhantomData<T>);
107
108/// A secret share base type
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct SecretShare<T>(pub(crate) String, pub(crate) PhantomData<T>);
111
112/// An extended public key base type
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct ExtendedPublicKey<T>(pub(crate) String, pub(crate) PhantomData<T>);
115
116/// An extended private key base type
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub struct ExtendedPrivateKey<T>(pub(crate) String, pub(crate) PhantomData<T>);
119
120impl<T> SecretShare<T> {
121 /// Returns the secret share as a string slice.
122 pub fn as_str(&self) -> &str {
123 &self.0
124 }
125}
126
127impl<T> From<String> for SecretShare<T> {
128 fn from(value: String) -> Self {
129 Self(value, PhantomData)
130 }
131}
132
133impl<T> ExtendedPublicKey<T> {
134 /// Returns the extended public key as a string slice.
135 pub fn as_str(&self) -> &str {
136 &self.0
137 }
138}
139
140impl<T> From<String> for ExtendedPublicKey<T> {
141 fn from(value: String) -> Self {
142 Self(value, PhantomData)
143 }
144}
145
146impl<T> ExtendedPrivateKey<T> {
147 /// Returns the extended private key as a string slice.
148 pub fn as_str(&self) -> &str {
149 &self.0
150 }
151}
152
153impl<T> From<String> for ExtendedPrivateKey<T> {
154 fn from(value: String) -> Self {
155 Self(value, PhantomData)
156 }
157}