Achilles' Tent Notes #13 written by Nathan Lilienthal on December 13, 2019.
- Achilles’ Tent Notes #8
- Achilles’ Tent Notes #9
- Achilles’ Tent Notes #10
- Achilles’ Tent Notes #11
- Achilles’ Tent Notes #12
- Achilles’ Tent Notes #13
Party Perspectives @P { ... }
When writing classic local programs (e.g. Rust 2018) all bindings have affinity
to the only local party, you (or @me
). To bridge the gap into the MPC
context, we allow global!
blocks @P { e }
to only evaluate into Some(e)
if the party running the block locally is @P
.
// Ideal syntax?
let r: i32@A = @A { rand() };
// Macro syntax? Closer to what exists today.
let r: Option<i32> = global!(@A, rand());
This composes with conceal
which can accept an Option<T>
from a party.
let s: Obliv<i32> = conceal!(@P <= @A, r);
conceal!
also gives shorthand for creating and consuming the Option
at
once.
let s: Obliv<i32> = conceal!(@P <= @A { rand() });
The following would fail to type check, since r
is only Some
for @A
, but
we’re saying here that @B
is providing this value. This implies that
Option<i32>
really isn’t going to work, we need i32@P
, which acts like an
optional.
let s: Obliv<i32> = conceal!(@P <= @B, r);
To participate in a protocol where we do not know the block which the other
party is executing, we can use concealed!(@P <= @B)
, which is shorthand for
conceal!(@P <= @B, None)
.
let s: Obliv<i32> = concealed!(@P <= @B);
This allows @A
and @B
to write partially separated code. For example below,
@A
calls rand
for s
, and @B
calls prompt
(perhaps reading from STDIN)
for t
, without each other knowing about how these binding’s values were
generated.
// @A's code:
let s = conceal!(@P <= @A { rand() });
let t = concealed!(@P <= @B);
// @B's code:
let s = concealed!(@P <= @A);
let t = conceal!(@P <= @B { prompt() });
Which could be rewritten to expose the rand
and read
calls globally as a
single source program once more.
let s = conceal!(@P <= @A { rand() });
let t = conceal!(@P <= @B { prompt() });
Finally, we want to reveal
some information from @P
to another party @A
.
let o: i32@A = reveal!(@P => @A, s + t);
Special @me
Party
TODO: More thought needs to be given to where @P
should show up in this
example below. I’m starting to wonder if it’s something that belongs on the
reference, related to the lifetimes.
fn is_mine<@P, 'a, T>(x: &'a T @P) -> bool {
if @P == @me {
true
} else {
false
}
}
// Always true.
let x = 1;
assert!(is_mine(&x));
// Fails for `@B`.
let x = @A { 1 };
assert!(is_mine(&x));
Example invertPerm
Function
// TODO: Purpose statements for the four helper functions.
fn randomPermutation() -> Vec<usize>;
fn invertPermutation(v: &[usize]) -> Vec<usize>;
fn waksmanBits(v: Vec<usize>) -> Vec<usize>;
fn waksmanPerm(v: Vec<Obliv<usize>>, w: Vec<Obliv<usize>>)
-> Vec<Obliv<usize>>;
fn invertPerm<@P, @A, @B>(x: Vec<Obliv<usize>>)
-> Vec<Obliv<usize>>
where @P: @A + @B
{
let (pa, pa_waksman) = conceal!(@P <= @A {
let lpa: Vec<usize> = randomPermutation();
let lpa_waksman: Vec<usize> = waksmansBits(&lpa);
(lpa, lpa_waksman)
});
let pb: Vec<Obliv<usize>> = waksmanPerm(&x, &pa_waksman);
let pb_local: Vec<usize@B> = pb.map(|e| reveal!(e, @P => @B)).collect();
let pbinv_waksman = conceal!(@P <= @B {
let pbinv: Vec<usize> = invertPermutation(&pb_local);
waksmanBits(&pbinv)
});
waksmanPerm(&pa, &pbinv_waksman)
}