Secure multi-party computation (Example in Golang)

Secure multi-party computation (Example in Golang)

Multiparty Computation (MPC) is a cryptographic technique that enables multiple parties to jointly compute a function over their private inputs while keeping those inputs confidential. The primary goal of MPC is to allow computations on sensitive data without revealing any information about the individual inputs to the other participants. This is achieved through the use of cryptographic protocols that ensure privacy, security, and correctness in collaborative computations.

In traditional computation, when multiple parties want to perform a joint computation, they usually have to share their data with a central authority or each other. This can be a security concern, especially when dealing with sensitive information. MPC addresses this issue by allowing parties to jointly compute a function while keeping their inputs private.

Multiparty Computation (MPC) is a cryptographic technique that enables multiple parties to jointly compute a function over their private inputs while keeping those inputs confidential. The primary goal of MPC is to allow computations on sensitive data without revealing any information about the individual inputs to the other participants. This is achieved through the use of cryptographic protocols that ensure privacy, security, and correctness in collaborative computations.

In traditional computation, when multiple parties want to perform a joint computation, they usually have to share their data with a central authority or each other. This can be a security concern, especially when dealing with sensitive information. MPC addresses this issue by allowing parties to jointly compute a function while keeping their inputs private.

Key characteristics of Multiparty Computation:

  • Privacy Preservation: MPC ensures that no party learns anything about the private inputs of others, except for what can be inferred from the publicly revealed output.

  • Security: The cryptographic protocols used in MPC are designed to withstand malicious behaviors, ensuring that parties cannot manipulate the computation to gain information about others' inputs.

  • Correctness: The final output of the computation is accurate, even though the computation is performed on encrypted or masked versions of the inputs.

  • Distributed Trust: Unlike traditional systems that rely on a central authority, MPC distributes trust among the participating parties, making it suitable for scenarios where mutual trust is limited.

MPC protocols often involve complex cryptographic techniques such as homomorphic encryption, secret sharing, and secure multi-party computation protocols. While these protocols add computational overhead, they provide a powerful framework for secure collaboration in scenarios where data privacy is paramount.

Implementation

In this Go implementation, we'll delve into a simplified MPC scenario involving three parties: Alice, Bob, and Charlie.

package main

import (
    "math/rand"
)

type Node struct {
    Value  float64
    Inbox  []float64
    Outbox []float64
    Z      float64
}

func (node *Node) RandomFloat64() float64 {
    min := 1.0
    max := 999999.0

    return min + rand.Float64()*(max-min)
}

func CreateNode(value float64) *Node {
    return &Node{Value: value}
}

func (node *Node) SendValueToNode(otherNode *Node) {
    outboxVal := node.RandomFloat64()
    node.Outbox = append(node.Outbox, outboxVal)
    otherNode.Inbox = append(otherNode.Inbox, outboxVal)
}

func (node *Node) PublishZ() {
    z := node.Value + (Sum(node.Inbox) - Sum(node.Outbox))
    node.Z = z
}

func Sum(val []float64) float64 {
    var sum float64
    for _, v := range val {
        sum += v
    }
    return sum
}

func Average(z []float64) float64 {
    var sum float64
    for _, v := range z {
        sum += v
    }
    avg := sum / float64(len(z))
    return avg
}

func main() {
    Alice := CreateNode(1000.00)
    Bob := CreateNode(2000.00)
    Charlie := CreateNode(3000.00)

    Alice.SendValueToNode(Bob)
    Alice.SendValueToNode(Charlie)

    Bob.SendValueToNode(Alice)
    Bob.SendValueToNode(Charlie)

    Charlie.SendValueToNode(Alice)
    Charlie.SendValueToNode(Bob)

    Alice.PublishZ()
    Bob.PublishZ()
    Charlie.PublishZ()

    z := []float64{Alice.Z, Bob.Z, Charlie.Z}
    avg := Average(z)

    println("Average: ", avg)
}

In the provided Go code, the Node struct serves as a blueprint for representing individual participants in a multiparty computation. Let's break down the key components of the Node struct:

type Node struct {
    ID     string
    Val    float64
    Inbox  []float64
    Outbox []float64
    Z      float64
}

func CreateNode(value float64) *Node {
    return &Node{Value: value}
}
  • ID: The ID field is a unique identifier assigned to each node. It distinguishes one participant from another within the computation.

  • Val: The Val field represents the initial private value associated with the node. This value serves as the starting point for the node's contribution to the collaborative computation.

  • Inbox: The Inbox field is an array that functions as a receptacle for incoming values from other nodes. During the computation, nodes securely exchange information, and the Inbox stores these received values.

  • Outbox: The Outbox field, also an array, acts as a repository for outgoing values. As part of the secure communication process, each node generates random values and shares them with other nodes, appending these values to their respective Outbox.

  • Z: The Z field represents the final computed value of the node. It is determined based on the node's initial value (Val), the values received from other nodes (Inbox), and the values sent to other nodes (Outbox). The computation results in a secure, jointly computed value that contributes to the overall collaborative result.

func (node *Node) SendValueToNode(otherNode *Node) {
    outboxVal := node.RandomFloat64()
    node.Outbox = append(node.Outbox, outboxVal)
    otherNode.Inbox = append(otherNode.Inbox, outboxVal)
}

func (node *Node) PublishZ() {
    z := node.Value + (Sum(node.Inbox) - Sum(node.Outbox))
    node.Z = z
}

The SendValueToNode method in the Node struct simulates a secure communication between two nodes. It generates a random float64 value using RandomFloat64, appends this value to the sender's (node) outbox, and then appends the same value to the receiver's (otherNode) inbox, mimicking a secure exchange of information between nodes.

The PublishZ method calculates the final value (Z) for a node in a multiparty computation. It uses the node's initial value (Value), subtracts the sum of values in its outbox from the sum of values in its inbox, and then adds the result to the initial value. The final computed value is stored in the Z field of the node.

In result, three nodes, representing individuals Alice, Bob, and Charlie, are created with initial values of 1000.00, 2000.00, and 3000.00, respectively. They then engage in a secure exchange of random values using the SendValueToNode method, where each node sends a random value to the other two nodes.

Following the exchange, each node publishes its final computed value (Z) using the PublishZ method. The final Z values for Alice, Bob, and Charlie are then collected into an array. Finally, the average of these computed values is calculated using the Average function, and the result is printed, representing the collaborative outcome of the multiparty computation. The code simulates a basic scenario of secure collaboration among multiple nodes, computing an average value without revealing individual inputs.