Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Commitment Protocol backend for Viaduct 2.0 (Circuit IR) #795

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .idea/kotlinScripting.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.aplcornell.viaduct.backends

import io.github.aplcornell.viaduct.backends.aby.ABYBackend
import io.github.aplcornell.viaduct.backends.cleartext.CleartextBackend
import io.github.aplcornell.viaduct.backends.commitment.CommitmentBackend

/** Combines all back ends that support circuit code generation. */
object CircuitCodeGenerationBackend : Backend by listOf(CleartextBackend, ABYBackend).unions()
object CircuitCodeGenerationBackend : Backend by listOf(CleartextBackend, ABYBackend, CommitmentBackend).unions()
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@

import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.asTypeName
import io.github.aplcornell.viaduct.circuitcodegeneration.AbstractCodeGenerator
import io.github.aplcornell.viaduct.circuitcodegeneration.Argument
import io.github.aplcornell.viaduct.circuitcodegeneration.CodeGeneratorContext
import io.github.aplcornell.viaduct.circuitcodegeneration.UnsupportedCommunicationException
import io.github.aplcornell.viaduct.circuitcodegeneration.kotlinType
import io.github.aplcornell.viaduct.circuitcodegeneration.receiveExpected
import io.github.aplcornell.viaduct.circuitcodegeneration.receiveReplicated
import io.github.aplcornell.viaduct.circuitcodegeneration.typeTranslator
import io.github.aplcornell.viaduct.runtime.commitment.Commitment
import io.github.aplcornell.viaduct.runtime.commitment.Committed
import io.github.aplcornell.viaduct.syntax.BinaryOperator
import io.github.aplcornell.viaduct.syntax.Host
import io.github.aplcornell.viaduct.syntax.Protocol
import io.github.aplcornell.viaduct.syntax.UnaryOperator
import io.github.aplcornell.viaduct.syntax.circuit.OperatorNode
import io.github.aplcornell.viaduct.syntax.operators.Maximum
import io.github.aplcornell.viaduct.syntax.operators.Minimum
import io.github.aplcornell.viaduct.backends.commitment.Commitment as CommitmentProtocol

class CleartextCircuitCodeGenerator(context: CodeGeneratorContext) : AbstractCodeGenerator(context) {

override fun operatorApplication(protocol: Protocol, op: OperatorNode, arguments: List<CodeBlock>): CodeBlock =
when (op.operator) {
Minimum ->
Expand Down Expand Up @@ -112,6 +121,128 @@
}
}

private fun createCommitment(
source: Protocol,
target: Protocol,
argument: Argument,
builder: CodeBlock.Builder,
): CodeBlock {
require(context.host in source.hosts + target.hosts)
if (source !is Local) {
throw UnsupportedCommunicationException(source, target, argument.sourceLocation)

Check warning on line 132 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L132

Added line #L132 was not covered by tests
}
require(source.hosts.size == 1 && source.host in source.hosts)
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
require(target is CommitmentProtocol)
if (target.cleartextHost != source.host || target.cleartextHost in target.hashHosts) {
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
throw UnsupportedCommunicationException(source, target, argument.sourceLocation)

Check warning on line 137 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L137

Added line #L137 was not covered by tests
}

val argType = kotlinType(argument.type.shape, typeTranslator(argument.type.elementType.value))
val sendingHost = target.cleartextHost
val receivingHosts = target.hashHosts
return when (context.host) {
sendingHost -> {
val tempName1 = context.newTemporary("CommitTemp")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to name these "committed" and "commitment". Giving them the same name isn't great. Also, Kotlin variables names should be lowercase.

val tempName2 = context.newTemporary("CommitTemp")
builder.addStatement(
"val %N = %T(%L)",
tempName1,
(Committed::class).asTypeName().parameterizedBy(argType),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need parameterizedBy here, the type annotation is not needed. This also means you can move argType down where it's actually used in the receive case.

argument.value,
)
builder.addStatement(
"val %N = %N.%M()",
tempName2,
tempName1,
MemberName(Committed.Companion::class.asClassName(), "commitment"),
)
receivingHosts.forEach {
builder.addStatement("%L", context.send(CodeBlock.of("%N", tempName2), it))
}
CodeBlock.of("%N", tempName1)
}

in receivingHosts -> {
val tempName3 = context.newTemporary("CommitTemp")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Better to name this commitment.

builder.addStatement(
"val %N = %L",
tempName3,
context.receive((Commitment::class).asTypeName().parameterizedBy(argType), source.host),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The receivers need to check with each other they received the same values.

)
CodeBlock.of("%N", tempName3)
}

else -> throw IllegalStateException()

Check warning on line 175 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L175

Added line #L175 was not covered by tests
}
}

private fun openCommitment(
source: Protocol,
target: Protocol,
argument: Argument,
builder: CodeBlock.Builder,
): CodeBlock {
require(source is CommitmentProtocol)
if (target !is Cleartext) {
throw UnsupportedCommunicationException(source, target, argument.sourceLocation)

Check warning on line 187 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L187

Added line #L187 was not covered by tests
}
require(context.host in source.hosts + target.hosts)
if (source.hashHosts != target.hosts || source.cleartextHost in source.hashHosts) {
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
throw UnsupportedCommunicationException(source, target, argument.sourceLocation)

Check warning on line 191 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L191

Added line #L191 was not covered by tests
}

val argType = kotlinType(argument.type.shape, typeTranslator(argument.type.elementType.value))
val sendingHost = source.cleartextHost
val receivingHosts = target.hosts
return when (context.host) {
sendingHost -> {
receivingHosts.forEach {
builder.addStatement("%L", context.send(argument.value, it))
}
CodeBlock.of("%L.value", argument.value)
}
in receivingHosts -> {
val tempName1 = context.newTemporary("CommitTemp")
builder.addStatement(
"val %N = %L",
tempName1,
context.receive((Committed::class).asTypeName().parameterizedBy(argType), source.cleartextHost),
)
val tempName2 = context.newTemporary("CommitTemp")
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
builder.addStatement(
"val %N = %L",
tempName2,
argument.value,
)
val tempName3 = context.newTemporary("CommitTemp")
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
builder.addStatement(
"val %N = %N.%N(%N)",
tempName3,
tempName2,
"open",
tempName1,
)

val peers = receivingHosts.filter { it != context.host }
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
if (peers.isNotEmpty()) {
for (host in peers) builder.addStatement("%L", context.send(CodeBlock.of(tempName3), host))
builder.addStatement(
"%L",
receiveExpected(
CodeBlock.of(tempName3),
context.host,
argType,
peers,
context,
),
)
}
CodeBlock.of("%N", tempName3)
}
else -> throw IllegalStateException()

Check warning on line 242 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L242

Added line #L242 was not covered by tests
}
}

override fun import(
protocol: Protocol,
arguments: List<Argument>,
Expand All @@ -127,6 +258,13 @@
CodeBlock.of("")
}
}
is CommitmentProtocol -> {
if (context.host in protocol.hosts + arg.protocol.hosts) {
openCommitment(arg.protocol, protocol, arg, builder)
} else {
CodeBlock.of("")

Check warning on line 265 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L265

Added line #L265 was not covered by tests
}
}

else -> throw UnsupportedCommunicationException(arg.protocol, protocol, arg.sourceLocation)
}
Expand All @@ -149,6 +287,13 @@
CodeBlock.of("")
}
}
is CommitmentProtocol -> {
if (context.host in protocol.hosts + arg.protocol.hosts) {
createCommitment(protocol, arg.protocol, arg, builder)
} else {
CodeBlock.of("")

Check warning on line 294 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/cleartext/CleartextCircuitCodeGenerator.kt#L294

Added line #L294 was not covered by tests
}
}

else -> throw UnsupportedCommunicationException(protocol, arg.protocol, arg.sourceLocation)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ object CommitmentBackend : Backend {

override fun codeGenerator(context: CodeGeneratorContext): CodeGenerator = CommitmentDispatchCodeGenerator(context)

override fun circuitCodeGenerator(context: CircuitCodeGeneratorContext): CircuitCodeGenerator = TODO()
override fun circuitCodeGenerator(context: CircuitCodeGeneratorContext): CircuitCodeGenerator = CommitmentCircuitCodeGenerator(context)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.github.aplcornell.viaduct.backends.commitment

import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.asTypeName
import io.github.aplcornell.viaduct.circuitcodegeneration.AbstractCodeGenerator
import io.github.aplcornell.viaduct.circuitcodegeneration.Argument
import io.github.aplcornell.viaduct.circuitcodegeneration.CodeGeneratorContext
import io.github.aplcornell.viaduct.circuitcodegeneration.UnsupportedCommunicationException
import io.github.aplcornell.viaduct.circuitcodegeneration.typeTranslator
import io.github.aplcornell.viaduct.runtime.commitment.Committed
import io.github.aplcornell.viaduct.syntax.Protocol
import io.github.aplcornell.viaduct.syntax.types.ValueType
import io.github.aplcornell.viaduct.runtime.commitment.Commitment as CommitmentValue

/**
* Backend code generator for the commitment protocol for the circuit IR.
*
* Throws an UnsupportedCommunicationException when used in an input program as a computation protocol.
* This is because the commitment protocol is only a storage format and not a computation protocol.
*/
class CommitmentCircuitCodeGenerator(context: CodeGeneratorContext) : AbstractCodeGenerator(context) {
override fun paramType(protocol: Protocol, sourceType: ValueType): TypeName {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this code belongs under storageType. paramType should be undefined (throw an error).

require(protocol is Commitment)
return when (context.host) {
protocol.cleartextHost -> (Committed::class).asTypeName().parameterizedBy(typeTranslator(sourceType))
in protocol.hashHosts -> (CommitmentValue::class).asTypeName().parameterizedBy(typeTranslator(sourceType))
else -> throw IllegalStateException()

Check warning on line 29 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt#L29

Added line #L29 was not covered by tests
}
}

override fun storageType(protocol: Protocol, sourceType: ValueType): TypeName {
return super.storageType(protocol, sourceType)

Check warning on line 34 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt#L34

Added line #L34 was not covered by tests
}

override fun import(protocol: Protocol, arguments: List<Argument>): Pair<CodeBlock, List<CodeBlock>> {
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
throw UnsupportedCommunicationException(arguments.first().protocol, protocol, arguments.first().sourceLocation)

Check warning on line 38 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt#L38

Added line #L38 was not covered by tests
}

override fun export(protocol: Protocol, arguments: List<Argument>): Pair<CodeBlock, List<CodeBlock>> {
adityanathan marked this conversation as resolved.
Show resolved Hide resolved
throw UnsupportedCommunicationException(arguments.first().protocol, protocol, arguments.first().sourceLocation)

Check warning on line 42 in compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt

View check run for this annotation

Codecov / codecov/patch

compiler/src/main/kotlin/io/github/aplcornell/viaduct/backends/commitment/CommitmentCircuitCodeGenerator.kt#L42

Added line #L42 was not covered by tests
}
}
20 changes: 20 additions & 0 deletions compiler/tests/should-pass/circuit/cleartext/Commitment1.circuit
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
host alice
host bob
host chuck

circuit fun <> move@Local(host = alice)(a: int[]) -> b: int[] {
return a
}

circuit fun <> move2@Replication(hosts = {bob, chuck})(a: int[]) -> b: int[] {
return a
}

fun <> main() -> {
val a@Local(host = alice) = alice.input<int[]>()
val c@Commitment(sender = alice, receivers = {bob, chuck}) = move<>(a)
val d@Replication(hosts = {bob, chuck}) = move2<>(c)
val = bob.output<int[]>(d)
val = chuck.output<int[]>(d)
return
}
18 changes: 18 additions & 0 deletions compiler/tests/should-pass/circuit/cleartext/Commitment2.circuit
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
host alice
host bob

circuit fun <> move@Local(host = alice)(a: int[]) -> b: int[] {
return a
}

circuit fun <> move2@Local(host = bob)(a: int[]) -> b: int[] {
return a
}

fun <> main() -> {
val a@Local(host = alice) = alice.input<int[]>()
val c@Commitment(sender = alice, receivers = {bob}) = move<>(a)
val d@Local(host = bob) = move2<>(c)
val = bob.output<int[]>(d)
return
}
1 change: 1 addition & 0 deletions examples/inputs/circuit/cleartext/Commitment1-alice.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5
Empty file.
Empty file.
1 change: 1 addition & 0 deletions examples/inputs/circuit/cleartext/Commitment2-alice.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5
Empty file.
Empty file.
1 change: 1 addition & 0 deletions examples/outputs/circuit/cleartext/Commitment1-bob.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5
1 change: 1 addition & 0 deletions examples/outputs/circuit/cleartext/Commitment1-chuck.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5
Empty file.
1 change: 1 addition & 0 deletions examples/outputs/circuit/cleartext/Commitment2-bob.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5