1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::missing_docs_in_private_items)]
#![allow(incomplete_features)]
#![allow(ambiguous_glob_reexports)]
#![feature(inherent_associated_types)]

//! Defines an MPC implementation over the a generic Arkworks curve that allows
//! for out-of-order execution of the underlying MPC circuit

use std::sync::{Arc, RwLock};

use algebra::{CurvePoint, Scalar};
use ark_ec::CurveGroup;

use rand::thread_rng;

pub mod algebra;
pub mod beaver;
#[cfg(feature = "benchmarks")]
pub mod buffer;
#[cfg(not(feature = "benchmarks"))]
pub(crate) mod buffer;
pub mod commitment;
pub mod error;
mod fabric;
pub mod gadgets;
#[cfg(feature = "benchmarks")]
pub use fabric::*;
#[cfg(not(feature = "benchmarks"))]
pub use fabric::{FabricInner, MpcFabric, ResultHandle, ResultId, ResultValue};
pub mod network;

// -------------
// | Constants |
// -------------

/// The first party
pub const PARTY0: u64 = 0;
/// The second party
pub const PARTY1: u64 = 1;

/// Generate a random curve point by multiplying a random scalar with the
/// curve group generator
pub fn random_point<C: CurveGroup>() -> CurvePoint<C> {
    let mut rng = thread_rng();
    CurvePoint::generator() * Scalar::random(&mut rng)
}

// --------------------
// | Crate-wide Types |
// --------------------

/// A type alias for a shared locked value
type Shared<T> = Arc<RwLock<T>>;

#[cfg(any(test, feature = "test_helpers"))]
pub mod test_helpers {
    //! Defines test helpers for use in unit and integration tests, as well as
    //! benchmarks
    use futures::Future;

    use crate::{
        beaver::{PartyIDBeaverSource, SharedValueSource},
        network::{MockNetwork, NoRecvNetwork, UnboundedDuplexStream},
        MpcFabric, PARTY0, PARTY1,
    };

    use ark_bn254::G1Projective as Bn254Projective;

    /// A curve used for testing algebra implementations, set to bn254
    pub type TestCurve = Bn254Projective;

    /// Create a mock fabric
    pub fn mock_fabric() -> MpcFabric<TestCurve> {
        let network = NoRecvNetwork::default();
        let beaver_source = PartyIDBeaverSource::default();

        MpcFabric::new(network, beaver_source)
    }

    /// Run a mock MPC connected by a duplex stream as the mock network
    ///
    /// This will spawn two tasks to execute either side of the MPC
    ///
    /// Returns the outputs of both parties
    pub async fn execute_mock_mpc<T, S, F>(f: F) -> (T, T)
    where
        T: Send + 'static,
        S: Future<Output = T> + Send + 'static,
        F: FnMut(MpcFabric<TestCurve>) -> S,
    {
        execute_mock_mpc_with_beaver_source(
            f,
            PartyIDBeaverSource::new(PARTY0),
            PartyIDBeaverSource::new(PARTY1),
        )
        .await
    }

    /// Execute a mock MPC by specifying a beaver source for party 0 and 1
    pub async fn execute_mock_mpc_with_beaver_source<B, T, S, F>(
        mut f: F,
        party0_beaver: B,
        party1_beaver: B,
    ) -> (T, T)
    where
        B: 'static + SharedValueSource<TestCurve>,
        T: Send + 'static,
        S: Future<Output = T> + Send + 'static,
        F: FnMut(MpcFabric<TestCurve>) -> S,
    {
        // Build a duplex stream to broker communication between the two parties
        let (party0_stream, party1_stream) = UnboundedDuplexStream::new_duplex_pair();
        let party0_fabric = MpcFabric::new(MockNetwork::new(PARTY0, party0_stream), party0_beaver);
        let party1_fabric = MpcFabric::new(MockNetwork::new(PARTY1, party1_stream), party1_beaver);

        // Spawn two tasks to execute the MPC
        let fabric0 = party0_fabric.clone();
        let fabric1 = party1_fabric.clone();
        let party0_task = tokio::spawn(f(fabric0));
        let party1_task = tokio::spawn(f(fabric1));

        let party0_output = party0_task.await.unwrap();
        let party1_output = party1_task.await.unwrap();

        // Shutdown the fabrics
        party0_fabric.shutdown();
        party1_fabric.shutdown();

        (party0_output, party1_output)
    }
}