data61 / MP-SPDZ

Versatile framework for multi-party computation
Other
931 stars 279 forks source link

[about initiating the Ring_Elements and Rq+Elements in the FHE directory] #1062

Closed jscode017 closed 1 year ago

jscode017 commented 1 year ago

Hi @mkskeller May I ask that is the ring_element class only a interger mod prime, and the rq_element class a ring that mods the X^N+1?

If so, I would like to ask that how could I initiate those variables For example: I would like to specify the mod p for the ring elements And also the mod and the N in X^N+1 for the rq_elements

Are there some examples or documents

Thanks :)

mkskeller commented 1 year ago

No. Ring_Element represents a polynomial modulo a prime and X^{N+1} whereas Rq_Element represents a polynomial modulo a prime or product of two prime and X^{N+1}. There is no documentation on these internals beyond the comments in the source code. This is because the code is limited to a specific kind of homomorphic encryption, that is, BGV with a prime cleartext modulus allowing up to one level of multiplication and such that all primes allow the FFT-based number theory transform. If you're happy with this, I recommend using the high-level interface: https://mp-spdz.readthedocs.io/en/latest/homomorphic-encryption.html If you're more interested in polynomial arithmetic, NTL might be a better library to use: https://libntl.org/

jscode017 commented 1 year ago

Thanks for the reply I am looking to build some lattice stuff, so I am looking into the Ring_Element and Rq_Element From what I have seen so far, I may need FFT_Data to init a Ring_Element May I ask how I could init an FFT_Data? In more details, I am finding a some example code to do as follow: It seems to me I need to call the void init(const Ring& Rg,const Zp_Data& PrD); https://github.com/data61/MP-SPDZ/blob/master/FHE/FFT_Data.h#L45

May I ask how could I init it with some variable like bigint than use that bigint to call void init(const Ring& Rg,const Zp_Data& PrD);? Thanks

mkskeller commented 1 year ago

You should be able to call init(const Ring& Rg, const Zp_Data Prd) after calling ::init(Rg, m) for the desired dimension m and Prd.init(p) for the desired prime bigint p. However, you should note that these functions have not been tested outside the parameters that are used in MP-SPDZ.

jscode017 commented 1 year ago

@mkskeller Thanks again for the reply! May I ask that If I am going to declare a ring element that has value equals 5 Could I do something as follows: Ring ring;


    init(ring, 32768);
    bigint p;
    generate_prime(p, 64, 16384);
    Zp_Data prd;
    prd.init(bigint(p));
    FFT_Data fft;
    fft.init(ring, prd);
    AddableVector<gfpvar_<0, 5>> a_vec(fft.get_R().phi_m());
    a_vec[0]=5;

Or should I assign 5 as some binary form and push to the vector?

And may I ask how could I call the mul function on ring_element correctly, the below code gives me segmentation fault

    Ring ring;
    init(ring, 32768);
    bigint p;
    generate_prime(p, 64, 16384);
    Zp_Data prd;
    prd.init(bigint(p));
    FFT_Data fft;
    fft.init(ring, prd);
    AddableVector<gfpvar_<0, 5>> a_vec(fft.get_R().phi_m());
    a_vec[0]=5;
    Ring_Element ring_ele(fft, polynomial, a_vec);

    AddableVector<gfpvar_<0, 5>> b_vec(fft.get_R().phi_m());
    b_vec[0]=7;
    Ring_Element ring_ele2(fft, polynomial, b_vec);
    Ring_Element ring_ele3(fft, polynomial, b_vec);
    mul(ring_ele3, ring_ele2, ring_ele);

Thanks a lot

mkskeller commented 1 year ago

You need to initialize gfpvar_<0,5> separately with gfpvar_<0,5>::init_field() if you want to use it. However, it might be easier to use Ring_Element::from(x) with vector<bigint> x.

jscode017 commented 1 year ago

@mkskeller thanks Then may I ask what should I pass in the vector if I would want to have a ring element which has a value like 5 Should I pass in a[0]=5 or in bit format a[0]=1, a[1]=0, a[2]=1

mkskeller commented 1 year ago

The first is correct.

jscode017 commented 1 year ago

Then may I also asks that in rq_element Why does it needs to read in two ring element? e.g.: Rq_Element a(Ring_Element(fftd[0], evaluation, a0), Ring_Element(fftd[1], evaluation, a1));

mkskeller commented 1 year ago

This is for the ciphertext modulus being a composite number (product of two primes). The two Ring_Element objects then are the representation according to the Chinese Remainder Theorem, which allows calculating the product of polynomials by element-wise product (the ultimate reason for the all infrastructure). The composite modulus is needed for ciphertext multiplication.

jscode017 commented 1 year ago

Thanks again So do it means that if I would want some Rq_Element of value 5 I could do likewise(based on 5 mod some big prime is also 5)?

bigint p;
bigint p2;
generate_prime(p, 64, 16384);
generate_prime(p2, 128, 32768);
Zp_Data prd;
prd.init(p);
Zp_Data prd2;
prd2.init(p2);
FFT_Data fft;
fft.init(ring, prd);
FFT_Data fft2;
fft2.init(ring2, prd2);
vector<bigint> a_vec(32768);
a_vec[0]=5;
Ring_Element ring_ele(fft, evaluation);
ring_ele.from(a_vec);
Ring_Element ring_ele2(fft2, evaluation);
ring_ele.from(a_vec);
Rq_Element a(ring_ele, ring_ele2);
mkskeller commented 1 year ago

I think that's right.

mkskeller commented 1 year ago

However, the Ring instances need to be the same.

jscode017 commented 1 year ago

Thanks Then may I ask that if I would like to have a Rq_element that modules n=p*q(where p and q is prime) Do I use different ring instances, or is there other way to do it?

mkskeller commented 1 year ago

I think there is a misunderstanding. What you want to do is supported, but it doesn't make sense to use two different instances of Ring because they represent the polynomial X^N+1 for some N, and this has to be same in both instances of Ring_Element.

jscode017 commented 1 year ago

Got it, sorry for the stupid question Then may I still ask how to init it with something like gfpvar(as above) does it mean for every element in the addable vector I have to call init_field? e.g.:

AddableVector<gfpvar_<0, 5>> a_vec(fft.get_R().phi_m());
for(auto a: a_vec) a.init_field(with the prime used in ring_element)
mkskeller commented 1 year ago

No, init_field() is a static method that only needs to be called once.

mkskeller commented 1 year ago

But I can only reiterate that using this kind of initialization has no benefit as it's slower.

jscode017 commented 1 year ago

@mkskeller Thanks again, I would probably stick to bigint then And may I ask how could I write Ring_Element and Rq_Element to file? like: https://github.com/data61/MP-SPDZ/blob/master/Protocols/fake-stuff.h#L91 In the fake offline?

mkskeller commented 1 year ago

You can use pack with an octetStream object and then the output method of said object.

jscode017 commented 1 year ago

Thanks

jscode017 commented 1 year ago

And may I ask where the code of != in fft data compare? It seems to me it is here: https://github.com/data61/MP-SPDZ/blob/master/FHE/FFT_Data.cpp#L137 but in https://github.com/data61/MP-SPDZ/blob/master/FHE/Ring_Element.cpp#L152 It seems to trigger another operator

mkskeller commented 1 year ago

The difference is that the first is called when you the objects as such (via operator overloading) whereas the second compares two pointers, that is, the two objects have the same in memory.

jscode017 commented 1 year ago

Thanks, so I suppose that if I would want to operate on two ring elements, I probably need to init them by some global fft data, ao they could have the same memory?

mkskeller commented 1 year ago

Correct. The pointer check is just a way to save time, and there is no reason in the existing implementation to have two different objects with the same content.

jscode017 commented 1 year ago

Then since I would have to write and read ring elements and rq elements from file, do you recommend maybe I should disable the memory address check in my implementation?(since if read from file they probably do not have the same memory address)

mkskeller commented 1 year ago

No. Even if you read elements from file, you will have to initialize the FFT_Data pointer in the Ring_Element. If you don't, you will likely encounter an invalid result or a segfault.