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

GFElementFuture ops should sometimes return sharefuture #311

Open
2 tasks
amiller opened this issue May 19, 2019 · 2 comments
Open
2 tasks

GFElementFuture ops should sometimes return sharefuture #311

amiller opened this issue May 19, 2019 · 2 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@amiller
Copy link
Contributor

amiller commented May 19, 2019

This logic for gfelement future is too conservative:
https://github.com/initc3/HoneyBadgerMPC/blob/dev/honeybadgermpc/progs/mixins/dataflow.py#L15

    def __binop_field(self, other, op):
        assert callable(op)

        if isinstance(other, int):
            other = self.context.field(other)

        res = GFElementFuture()
        ...

Since it always returns a GFElementFuture.
But it should be possible to multiply a GFElementFuture by a Share, which should result in a ShareFuture. This is how beaver multiplication works in mpc.py:test_prog1:

    e = (y - b).open()
    await d
    await e

    # This is a random share of x*y
    logging.info(f'type(d): {type(d)}')  # GFElementFuture
    logging.info(f'type(b): {type(b)}')  # Share
    xy = d*e + d*b + e*a + ab

    logging.info(f'type(x): {type(x)}')  # Share
    logging.info(f'type(y): {type(y)}')  # Share
    logging.info(f'type(xy): {type(xy)}')  # GFElementFuture, but should be Share
    x_, y_, xy_ = await x.open(), await y.open(), await xy.open()

The solution would be:

  • add Share and ShareFuture to the typecheck options for GFElementFuture, and
  • have the return object for this be ShareFuture if the arg type is Share or ShareFuture
@amiller amiller added the bug Something isn't working label May 19, 2019
@amiller amiller added this to the 0.1 (alpha) milestone May 19, 2019
@Drake-Eidukas
Copy link
Contributor

I think we can actually accomplish this by modifying the type-checking.
If a special built-in method (__add__, for example) returns NotImplemented instead of raising an AssertionError, then it will call __radd__ on the other operand. Thus, we would be able to call code like fut + share and it will call share.__radd__(fut) and we don't have to have duplicate logic to handle this.

We can achieve this logic by using if __debug__ to see if we're not running with -O, as this will completely strip out the contents of the if statement.

@Drake-Eidukas
Copy link
Contributor

Example:

class TypeC:
    def __init__(self, val):
        self.val = val    

    def __add__(self, other):
        if not isinstance(other, TypeC):
            return NotImplemented           

        return TypeC(self.val + other.val)

class TypeD:
    def __init__(self, val):
        self.val = val

    def __add__(self, other):
        if not isinstance(other, (TypeC, TypeD)):
            return NotImplemented

        return TypeD(self.val + other.val)

    def __radd__(self, other):
        if not isinstance(other, (TypeC, TypeD)):
            return NotImplemented

        return TypeD(self.val + other.val)

c = TypeC(4)
d = TypeD(5)

Then, calling c+d will return a TypeD.

@amiller amiller modified the milestones: 0.1 (alpha), 1.0 (beta) Jun 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants