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

mpc.trunc not accurate for values of f > 3 #88

Closed
AlessandroAmadoriTNO opened this issue Apr 24, 2024 · 4 comments
Closed

mpc.trunc not accurate for values of f > 3 #88

AlessandroAmadoriTNO opened this issue Apr 24, 2024 · 4 comments

Comments

@AlessandroAmadoriTNO
Copy link

AlessandroAmadoriTNO commented Apr 24, 2024

Hello @lschoe

I hope you are doing well 😄

I was testing around the mpc.trunc function and I noticed that the result for "high" values of f does not return an accurate result:

This is the code I used to test it

import math
from random import randint

from mpyc.runtime import mpc

secint = mpc.SecInt(l=32)

async def main():
    test_number = randint(0, 10**9)
    async with mpc:
        sec_number = mpc.input(secint(test_number), senders=0)

        scaling_factors = range(0, int(math.log2(abs(test_number))))
        output_value = await mpc.output(sec_number)

        for f in scaling_factors:
            print("--------------------------")
            sec_truncated_number = await mpc.output(mpc.trunc(sec_number, f))
            clear_rounded_number = round(test_number / 2**f)
            print(f"{output_value=}")
            print(f"Non Rounded Output: {test_number /2**f}")
            print(f"Scaling factor f = {f}")
            print(f"{clear_rounded_number=}")
            print(f"{sec_truncated_number=}")

if __name__ == "__main__":
    mpc.run(main())

and already for f> 3 the output was a very large negative number completely off from what I expected.
For example:

output_value=320134517
Non Rounded Output: 1250525.45703125
Scaling factor f = 8
clear_rounded_number=1250525
sec_truncated_number=-1080863910567668503

I played around with the source code in runtime and I noticed that in https://github.com/lschoe/mpyc/blob/master/mpyc/runtime.py#L794

the computation works correctly until the right shift is performed. Does it have to do with the fact that the element a-c+r.value is a finite field element and not an integer?

I get the same behavior for mpyc 0.9 and 0.10 and I have tested it with 1 and 3 players

Thank you!

@lschoe
Copy link
Owner

lschoe commented Apr 24, 2024

Hi @AlessandroAmadoriTNO, interesting question!

You are trying to use mpc.trunc() with secure integers rather than with secure fixed-point numbers. That's not working currently, as it is designed for use with secure fixed-point numbers. This has to do with the available headroom. For secure integers, the headroom is k bits, for statistical security parameter k. For secure fixed-point numbers the headroom is k+f bits, so with an extra f bits. You are experiencing overflows (wrap arounds modulo the prime of the underlying finite field) because of the smaller headroom for secure integers.

To get better results, while working with secure integers still, you can set secint as follows:

secint = mpc.SecInt(l=64)
p = secint.field.modulus  # grab the extra large prime modulus 
secint = mpc.SecInt(l=32, p=p)  # sets bit length to l and uses the given (oversized) p

Or, you can work with secure fixed-point numbers, but then of double bit length to make your test numbers fit as integers, setting secint as follows:

secint = mpc.SecFxp(l=64)

This way mpc.trunc() still returns correct results, I think.

And, also you can use the keyword parameter l to mpc.trunc() by changing your call in the above code to mpc.trunc(sec_number, f, 32) and this time setting secint = mpc.SecInt(64) to make things fit with the 0 to 10**9 range you are using in your tests.

@lschoe
Copy link
Owner

lschoe commented Apr 25, 2024

I have a made a small adjustment to mpc.trunc() (and also to mpc.mp_trunc()) to make it work for secure integers as well. You can now directly run your test program above to get the desired results.

To make sure all parties do the same number of iterations, change the two lines in the middle of the program to:

        output_value = await mpc.output(sec_number)
        scaling_factors = range(0, int(math.log2(abs(output_value))))

@RobertWezemanTNO
Copy link

Perfect! I tested it and it seems to fix our issues. Thank you for the quick fix.

Will a new release v0.11 be made?

@lschoe
Copy link
Owner

lschoe commented Apr 25, 2024

OK, nice.

There will be a new release maybe in a few months. For the latest version install mpyc directly from GitHub.

@lschoe lschoe closed this as completed Apr 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants