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}