Damgard-Jurik Scheme of Paillier - Klefki 1.7 Documentation
Damgard-Jurik Scheme of Paillier - Klefki 1.7 Documentation
Damgard-Jurik Scheme of Paillier - Klefki 1.7 Documentation
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.
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 𝑥 ∈ 𝐻 .
Let 𝜆 be the 𝑙𝑐𝑚 of 𝑝 − 1 and 𝑞 − 1. By the Chinese Remainder Theorem, choose 𝑑 such that 𝑑 mod
𝑛 ∈ 𝑍𝑛 and 𝑑 = 0 mod 𝜆.
{ 𝑍𝑛 mod 𝑁 }
0 mod 𝜙(𝑁)
𝑑≡
[2]: k = 256
p, q = generate_prime(k), generate_prime(k)
assert p != q
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)
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
[8]: c = encrypt(i, r)
Decryption
Given a ciphertext 𝑐, first compute 𝑐𝑑 mod 𝑛𝑠+1 , Clearly, if 𝑐 = 𝐸(𝑣, 𝑟) , we get
𝑠
𝑐𝑑 = (𝑔𝑖 𝑟𝑛 )𝑑
𝑠
= ((1 + 𝑛)𝑖𝑗 𝑥𝑖 𝑟𝑛 )𝑑
𝑠
= (1 + 𝑛)𝑗𝑖𝑑 (𝑥𝑖 𝑟𝑛 )𝑑
𝑠 𝑠
= (1 + 𝑛)𝑗𝑖𝑑 mod 𝑛 (𝑥𝑖 𝑟𝑛 )𝑑 mod 𝜆
𝑠
= (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]: True
[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 𝑛.
[28]: k = 256
[29]: p, q = (p - 1) // 2, (q - 1) // 2
[30]: n = p * q
m = p_ * q_
[32]: j = generate_prime(k)
assert gcd(j, n) == 1
x = randfield(H)
g = MG((MG(1 + n) ** j) * x)
[36]: k = 3
l = n = 6
[37]: ssss.setup(d, k, 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
[29]: m = 42
[31]: djp.D(djp.E(m)).value == m
[31]: True
[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.
[ ]: