Commit 09889f67 authored by Anders Jensen Løvig's avatar Anders Jensen Løvig
Browse files

Implemenet and test protocol.

parent 2654ff5f
package main
import (
"fmt"
"math"
"math/rand"
)
const (
BloodType_On = 0
BloodType_Op = 1
BloodType_An = 2
BloodType_Ap = 3
BloodType_Bn = 4
BloodType_Bp = 5
BloodType_ABn = 6
BloodType_ABp = 7
)
// T is the blood type compatibily truth table, with rows being the recipient's
// blood type and columns being the donor's blood type.
var BloodTable = [][]bool{
{true, false, false, false, false, false, false, false},
{true, true, false, false, false, false, false, false},
{true, false, true, false, false, false, false, false},
{true, true, true, true, false, false, false, false},
{true, false, false, false, true, false, false, false},
{true, true, false, false, true, true, false, false},
{true, false, true, false, true, false, true, false},
{true, true, true, true, true, true, true, true},
}
// The parameters for the protocol
type Params struct {
n int
nPow int // pow(2, n)
}
// Creates a new Params with n and 2^n.
func NewParams(n int) *Params {
return &Params{
n: n,
nPow: int(math.Pow(2, float64(n))),
}
}
// mod computes the modulo a%n but handles negative a correctly.
func mod(a, n int) int {
return (a%n + n) % n
}
type Dealer struct {
// Input to Alice
r int
ma [][]bool
// Input to Bob
s int
mb [][]bool
}
// NewDealer creates a dealer with initialized parameters.
func NewDealer(seed int64, T [][]bool, params *Params) *Dealer {
rand := rand.New(rand.NewSource(seed))
var d Dealer
// 1. Choose two shifts r and s
d.r = rand.Intn(params.nPow)
d.s = rand.Intn(params.nPow)
// 2. Choose a matrix Mb ...
d.mb = make([][]bool, params.nPow)
for i := range d.mb {
row := make([]bool, params.nPow)
for j := range row {
row[j] = rand.Intn(2) == 0 // random bool
}
d.mb[i] = row
}
// 3. Compute a matrix Ma ...
d.ma = make([][]bool, params.nPow)
for i := range d.ma {
row := make([]bool, params.nPow)
for j := range row {
ir := mod(i-d.r, params.nPow)
js := mod(j-d.s, params.nPow)
row[j] = d.mb[i][j] != T[ir][js] // xor
}
d.ma[i] = row
}
return &d
}
func (d *Dealer) DealA() (int, [][]bool) {
return d.r, d.ma
}
func (d *Dealer) DealB() (int, [][]bool) {
return d.s, d.mb
}
// Alice represents the recipient in the protocol.
type Alice struct {
params *Params
x int
r int
ma [][]bool
u int
v int
zb bool
}
func NewAlice(x, r int, ma [][]bool, params *Params) *Alice {
return &Alice{
params: params,
x: x,
r: r,
ma: ma,
u: mod(x+r, params.nPow),
}
}
func (p *Alice) Send() int {
return p.u
}
func (p *Alice) Receive(v int, zb bool) {
p.v = v
p.zb = zb
}
func (p *Alice) Output() bool {
return p.ma[p.u][p.v] != p.zb
}
// Bob represents the donor in the protocol.
type Bob struct {
params *Params
y int
s int
mb [][]bool
u int
v int
}
func NewBob(y, s int, mb [][]bool, params *Params) *Bob {
return &Bob{
params: params,
y: y,
s: s,
mb: mb,
v: mod(y+s, params.nPow),
}
}
func (p *Bob) Receive(u int) {
p.u = u
}
func (p *Bob) Send() (int, bool) {
return p.v, p.mb[p.u][p.v]
}
func RunProtocol(x, y int) bool {
// Init protocol parameters and dealer
params := NewParams(3)
dealer := NewDealer(100, BloodTable, params)
// Init Alice
r, ma := dealer.DealA()
alice := NewAlice(x, r, ma, params)
// Init Bob
s, mb := dealer.DealB()
bob := NewBob(y, s, mb, params)
bob.Receive(alice.Send())
alice.Receive(bob.Send())
return alice.Output()
}
func main() {
z := RunProtocol(BloodType_ABp, BloodType_Bp)
if z == BloodTable[BloodType_ABp][BloodType_Bp] {
fmt.Println("Protocol succeded")
} else {
fmt.Println("Protocol failed")
}
}
package main
import (
"testing"
)
func TestBloodTable(t *testing.T) {
if len(BloodTable) != 8 {
t.Fatalf("Expected 8 rows, got %d", len(BloodTable))
}
for i := range BloodTable {
if len(BloodTable[i]) != 8 {
t.Fatalf("Expected columns in row %d, got %d", i, len(BloodTable))
}
}
}
func TestParams(t *testing.T) {
p := NewParams(7)
if p.n != 7 {
t.Fatalf("Expected 7, got %d", p.n)
}
if p.nPow != 128 {
t.Fatalf("Expected 128, got %d", p.nPow)
}
}
func TestProtocol(t *testing.T) {
// Runs the protocol for all combinations of recipient and donor.
for x := range BloodTable {
for y := range BloodTable[x] {
if z := RunProtocol(x, y); z != BloodTable[x][y] {
t.Fatalf("Failed blood compatibility test for index [%d,%d]. Expected %t, got %t", x, y, !z, z)
}
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment