Damgard-Jurik Scheme of Paillier - Klefki 1.7 Documentation

Download as pdf or txt
Download as pdf or txt
You are on page 1of 6

Damgard-Jurik Scheme of Paillier

Fork me on GitHub

Generalisation
The publickey cryptosystem uses computations modulo 𝑛𝑠+1 where 𝑛 is an 𝑅𝑆𝐴 modulus and 𝑠 is a
natural number. It contains Paillier’s scheme as a special case by setting 𝑠 = 1

We start from the observation that if 𝑛 = 𝑝𝑞, 𝑝, 𝑞 odd primes, then 𝑍𝑛∗𝑠+1 as a multiplicative group is a
direct product 𝐺 × 𝐻 , where 𝐺 ic cyclic of order 𝑛𝑠 and 𝐻 is isomorphic to 𝑍𝑛∗ , which follows directly
from elementary number theory.

¯ = 𝑍 ∗𝑛𝑠+1 /𝐻 is also cyclic of order 𝑛𝑠 . For an arbitary element 𝑎 ∈ 𝑍𝑛𝑠+1 , we let


Thus, the factor group 𝐺
𝑎¯ 𝐻 we denote the element represented by 𝑎 in the factor group 𝐺 ¯.

Lemma 1: For any 𝑠 < 𝑝, 𝑞, the element 𝑛 + 1 has order 𝑛𝑠 in 𝑍𝑛𝑠+1 .

It is easy to compute 𝑖 from (1 + 𝑛)𝑖 mod 𝑛𝑠+1 . If we define the function 𝐿() by 𝐿(𝑏) = (𝑏 − 1)/𝑛 then
clealy we have:

(2) (𝑠)
𝑖 𝑖 𝑠−1
𝐿((1 + 𝑛)𝑖 mod 𝑛𝑠+1 ) = (1 + 𝑛+⋯+ 𝑛 ) mod 𝑛𝑠

Key Generation
On input the security parameter 𝑘, choose an 𝑅𝑆𝐴 modulus 𝑛 = 𝑝𝑞 of length 𝑘 bits. Also choose an
element 𝑔 ∈ 𝑍𝑛𝑠+1 such that 𝑔 = (1 + 𝑛)𝑗 𝑥 mod 𝑛𝑠+1 for a known 𝑗 relatively prime to 𝑛 and 𝑥 ∈ 𝐻 .

This can be done, 𝑒. 𝑔, by choosing 𝑗, 𝑥 as random first and computing 𝑔;

Let 𝜆 be the 𝑙𝑐𝑚 of 𝑝 − 1 and 𝑞 − 1. By the Chinese Remainder Theorem, choose 𝑑 such that 𝑑 mod
𝑛 ∈ 𝑍𝑛 and 𝑑 = 0 mod 𝜆.

{ 𝑍𝑛 mod 𝑁 }
0 mod 𝜙(𝑁)
𝑑≡

Any such choice of 𝑑 will work in the following.

Now the pubkey is 𝑛, 𝑔 while the secret key is 𝑑.

[1]: from klefki.types.algebra.meta import field


from klefki.types.algebra.utils import randfield
from klefki.numbers.primes import generate_prime
from klefki.crypto.damgard_jurik import damgard_jurik_reduce
from klefki.numbers import lcm
from random import randint
from math import gcd

[2]: k = 256

p, q = generate_prime(k), generate_prime(k)
assert p != q

# Paillier's scheme is a special case by setting s=1


s = 3
n = p * q

lam = lcm((p - 1), (q - 1))


assert gcd(n, lam) == 1

G = field(n**s, "G") # n ** s == n if s = 1
# multiplicative group
MG = field(n ** (s+1), "N^{s+1}") # n ** (s +1 ) == n2 in pailer case
H = field(n, "H")
LG = field(lam, "LCMGroup")

[3]: j = generate_prime(k)
assert gcd(j, n) == 1

x = randfield(H)
g = MG((MG(1 + n) ** j) * x)

[4]: from klefki.numbers import crt

[5]: # Find d such that d = 0 mod lambda and d = 1 mod n^s


d = crt(a_list=[0, 1], n_list=[LG.P, G.P])
assert d % G.P == 1
assert d % LG.P == 0

[6]: pubkey = (n, g)


privkey = d

Encryption
The paintext set is 𝑍𝑛𝑠 . Given a paintext 𝑖, choose a random 𝑟 ← 𝑍𝑛∗𝑠+1 , and lte the cipertext be
𝑠
𝐸(𝑖, 𝑟) = 𝑔𝑖 𝑟𝑛 mod 𝑛𝑠+1

[7]: r = randfield(MG)
i = 31415926

def encrypt(i, r):


return g ** i * r ** (n**s)

[8]: c = encrypt(i, r)

Decryption
Given a ciphertext 𝑐, first compute 𝑐𝑑 mod 𝑛𝑠+1 , Clearly, if 𝑐 = 𝐸(𝑣, 𝑟) , we get
𝑠
𝑐𝑑 = (𝑔𝑖 𝑟𝑛 )𝑑
𝑠
= ((1 + 𝑛)𝑖𝑗 𝑥𝑖 𝑟𝑛 )𝑑
𝑠
= (1 + 𝑛)𝑗𝑖𝑑 (𝑥𝑖 𝑟𝑛 )𝑑
𝑠 𝑠
= (1 + 𝑛)𝑗𝑖𝑑 mod 𝑛 (𝑥𝑖 𝑟𝑛 )𝑑 mod 𝜆
𝑠
= (1 + 𝑛)𝑗𝑖𝑑 mod 𝑛

𝑔𝑑 = ((1 + 𝑛)𝑗 𝑥)𝑑


= (1 + 𝑛)𝑗𝑑 𝑥𝑑
mod 𝑛 2 𝑑
= (1 + 𝑛)𝑗𝑑 𝑥 mod 𝜆

[9]: c ** d == (g ** i * r ** (n**s))**d \
== (MG((MG(1 + n) ** j) * x) ** i * r ** (n**s)) ** d \
== (MG(MG(1 + n) ** (j*i)) * (MG(x) ** i) * r ** (n**s)) ** d \
== MG(MG(1 + n) ** (j * i * d)) * (((MG(x) ** i) * r ** (n**s)) ** d)
[9]: True

[10]: (((MG(x) ** i) * r ** (n**s)) ** LG(d)).value == 1

[10]: True

[11]: G(damgard_jurik_reduce((c ** d).value, n, s)) * ~G(damgard_jurik_reduce((g ** d).value, n,

[11]: G::31415926
A Threshold Variant of Paillier
We can solve our problem by letting the servers help us compute 𝐸(𝑖, 𝑟)𝑑 mod 𝑛𝑠+1 . Then if we use
𝑔 = 𝑛 + 1 and choose d such that 𝑑 = 1𝑚𝑜𝑑𝑛𝑠 and 𝑑 = 0 mod 𝜆, the remaining part of the decryption
is easy to do without knowledge of 𝑑.

Key generation
We find 2 primes 𝑝 and 𝑞, that satisifies 𝑝 = 2𝑝′ + 1 and 𝑞 = 2𝑞 ′ + 1, where 𝑝′ and 𝑞 ′ are primes and
different from 𝑝, 𝑞.

We set 𝑛 = 𝑝𝑞 and 𝑚 = 𝑝′ 𝑞 ′ ,we decide some 𝑠 > 0, thus the paintext space will be 𝑍𝑛𝑠 .

We pick 𝑑 to satisfy:

{1 mod 𝑛𝑠 }
0 mod 𝑚
𝑑≡

And share 𝑑 with 𝑆𝑆𝑆𝑆 in 𝑍𝑛𝑠 𝑚, the secret share of the i’th authority will be 𝑠𝑖 = 𝑓(𝑖) for 1 ≤ 𝑖 ≤ 𝑙, and
the pubkey will be 𝑛.

[27]: from klefki.crypto.ssss import SSSS

[28]: k = 256

p_, q_ = generate_prime(k), generate_prime(k)


assert p != q

[29]: p, q = (p - 1) // 2, (q - 1) // 2

[30]: n = p * q
m = p_ * q_

[31]: G = field(n**s, "G") # n ** s == n if s = 1


# multiplicative group
MG = field(n ** (s+1), "N^{s+1}") # n ** (s +1 ) == n2 in pailer case
H = field(n, "H")
LG = field(m, "MGroup")

[32]: j = generate_prime(k)
assert gcd(j, n) == 1
x = randfield(H)
g = MG((MG(1 + n) ** j) * x)

[33]: d = crt(a_list=[0, 1], n_list=[m, n])

[34]: F = field(n**s * m, "n^sm")

[35]: ssss = SSSS(F)

[36]: k = 3
l = n = 6

[37]: ssss.setup(d, k, n)

[37]: <klefki.crypto.ssss.SSSS at 0x1076f8be0>

[38]: shares = [ssss.join(i) for i in range(1, n)]

Encryption
[39]: def encrypt(i, r):
return g ** m * r ** (n**s)

[40]: r = randfield(MG)
i = 31415926

[41]: c = encrypt(i, r)

Share decryption
The i’th authority will compute 𝑐𝑖 = 𝑐2Δ𝑠𝑖 , where 𝑐 is the ciphertext, Δ = 𝑙!

If we have the required k (or more) number of shares with a correct proof, we can combine them into the
result by taking a subset S of k shares and combine them to

2𝜆𝑆0,𝑖
𝑐′ =

𝑐𝑖
𝑖∈𝑆

Where:

−𝑖
𝜆𝑠0,𝑖 = Δ

∈𝑍

𝑖 − 𝑖′
𝑖 ∈𝑆;𝑖

Implementation
[27]: from klefki.crypto.damgard_jurik import DJPaillier
from klefki.numbers.primes import generate_prime

[28]: P, Q = generate_prime(256), generate_prime(256)


s = 3

[29]: m = 42

[30]: djp = DJPaillier(P, Q, s)

[31]: djp.D(djp.E(m)).value == m

[31]: True

Note that the threshold DJP is imported via https://github.com/cryptovoting/damgard-jurik

[32]: from klefki.crypto.damgard_jurik import ts_dj

public_key, private_key_ring = ts_dj.keygen(


n_bits=512,
s=3,
threshold=100,
n_shares=300
)

[33]: private_key_ring.i_list

[33]: [mpz(124),
mpz(186),
mpz(54),
mpz(239),
mpz(252),
mpz(269),
mpz(136),
mpz(221),
mpz(109),
mpz(29),
mpz(74),
mpz(212),
mpz(90),
mpz(259),
mpz(13),
mpz(172),
mpz(231),
mpz(32),
mpz(43),
mpz(194),
mpz(53),
mpz(3),
mpz(176),
mpz(246),
mpz(300),
mpz(37),
mpz(14),
mpz(190),
mpz(125),
mpz(208),
mpz(233),
mpz(297),
mpz(42),
mpz(127),
mpz(30),
mpz(236),
mpz(188),
mpz(290),
mpz(248),
mpz(81),
mpz(211),
mpz(95),
mpz(143),
mpz(187),
mpz(170),
mpz(46),
mpz(110),
mpz(8),
mpz(112),
mpz(150),
mpz(68),
mpz(52),
mpz(79),
mpz(12),
mpz(126),
mpz(103),
mpz(86),
mpz(139),
mpz(93),
mpz(135),
mpz(134),
mpz(18),
mpz(223),
mpz(262),
mpz(104),
mpz(218),
mpz(60),
mpz(10),
mpz(131),
mpz(162),
mpz(261),
mpz(267),
mpz(284),
mpz(44),
mpz(140),
mpz(65),
mpz(33),
mpz(204),
mpz(230),
mpz(282),
mpz(39),
mpz(58),
mpz(4),
mpz(203),
mpz(27),
mpz(88),
mpz(106),
mpz(242),
mpz(67),
mpz(210),
mpz(50),
mpz(111),
mpz(173),
mpz(180),
mpz(219),
mpz(59),
mpz(107),
mpz(289),
mpz(57),
mpz(174)]

[34]: m = 42
c = public_key.encrypt(m)
private_key_ring.decrypt(c)
[34]: mpz(42)

Ref:
I. Damg˚ard and M. Jurik. A generalisation, a simplification and some applications of paillier’s
proba- bilistic public-key system. In Public Key Cryptography, pages 119–136, 2001.

Damgard-Jurik implementation https://github.com/cryptovoting/damgard-jurik

[ ]:

You might also like