xref: /aosp_15_r20/external/private-join-and-compute/private_join_and_compute/crypto/elgamal.cc (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
1 /*
2  * Copyright 2019 Google LLC.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     https://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "private_join_and_compute/crypto/elgamal.h"
17 
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/log/check.h"
23 #include "private_join_and_compute/crypto/big_num.h"
24 #include "private_join_and_compute/crypto/ec_group.h"
25 #include "private_join_and_compute/crypto/ec_point.h"
26 #include "private_join_and_compute/util/status.inc"
27 
28 namespace private_join_and_compute {
29 
30 namespace elgamal {
31 
32 StatusOr<std::pair<std::unique_ptr<PublicKey>, std::unique_ptr<PrivateKey>>>
GenerateKeyPair(const ECGroup & ec_group)33 GenerateKeyPair(const ECGroup& ec_group) {
34   ASSIGN_OR_RETURN(ECPoint g, ec_group.GetFixedGenerator());
35   BigNum x = ec_group.GeneratePrivateKey();
36   ASSIGN_OR_RETURN(ECPoint y, g.Mul(x));
37 
38   std::unique_ptr<PublicKey> public_key(
39       new PublicKey({std::move(g), std::move(y)}));
40   std::unique_ptr<PrivateKey> private_key(new PrivateKey({std::move(x)}));
41 
42   return {{std::move(public_key), std::move(private_key)}};
43 }
44 
GeneratePublicKeyFromShares(const std::vector<std::unique_ptr<elgamal::PublicKey>> & shares)45 StatusOr<std::unique_ptr<PublicKey>> GeneratePublicKeyFromShares(
46     const std::vector<std::unique_ptr<elgamal::PublicKey>>& shares) {
47   if (shares.empty()) {
48     return InvalidArgumentError(
49         "ElGamal::GeneratePublicKeyFromShares() : empty shares provided");
50   }
51   ASSIGN_OR_RETURN(ECPoint g, (*shares.begin())->g.Clone());
52   ASSIGN_OR_RETURN(ECPoint y, (*shares.begin())->y.Clone());
53   for (size_t i = 1; i < shares.size(); i++) {
54     CHECK(g.CompareTo((*shares.at(i)).g))
55         << "Invalid public key shares provided with different generators g";
56     ASSIGN_OR_RETURN(y, y.Add((*shares.at(i)).y));
57   }
58 
59   return absl::WrapUnique(new PublicKey({std::move(g), std::move(y)}));
60 }
61 
Mul(const elgamal::Ciphertext & ciphertext1,const elgamal::Ciphertext & ciphertext2)62 StatusOr<elgamal::Ciphertext> Mul(const elgamal::Ciphertext& ciphertext1,
63                                   const elgamal::Ciphertext& ciphertext2) {
64   ASSIGN_OR_RETURN(ECPoint u, ciphertext1.u.Add(ciphertext2.u));
65   ASSIGN_OR_RETURN(ECPoint e, ciphertext1.e.Add(ciphertext2.e));
66   return {{std::move(u), std::move(e)}};
67 }
68 
Exp(const elgamal::Ciphertext & ciphertext,const BigNum & scalar)69 StatusOr<elgamal::Ciphertext> Exp(const elgamal::Ciphertext& ciphertext,
70                                   const BigNum& scalar) {
71   ASSIGN_OR_RETURN(ECPoint u, ciphertext.u.Mul(scalar));
72   ASSIGN_OR_RETURN(ECPoint e, ciphertext.e.Mul(scalar));
73   return {{std::move(u), std::move(e)}};
74 }
75 
GetZero(const ECGroup * group)76 StatusOr<Ciphertext> GetZero(const ECGroup* group) {
77   ASSIGN_OR_RETURN(ECPoint u, group->GetPointAtInfinity());
78   ASSIGN_OR_RETURN(ECPoint e, group->GetPointAtInfinity());
79   return {{std::move(u), std::move(e)}};
80 }
81 
CloneCiphertext(const Ciphertext & ciphertext)82 StatusOr<Ciphertext> CloneCiphertext(const Ciphertext& ciphertext) {
83   ASSIGN_OR_RETURN(ECPoint clone_u, ciphertext.u.Clone());
84   ASSIGN_OR_RETURN(ECPoint clone_e, ciphertext.e.Clone());
85   return {{std::move(clone_u), std::move(clone_e)}};
86 }
87 
IsCiphertextZero(const Ciphertext & ciphertext)88 bool IsCiphertextZero(const Ciphertext& ciphertext) {
89   return ciphertext.u.IsPointAtInfinity() && ciphertext.e.IsPointAtInfinity();
90 }
91 
92 }  // namespace elgamal
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 // PUBLIC ELGAMAL
96 ////////////////////////////////////////////////////////////////////////////////
97 
ElGamalEncrypter(const ECGroup * ec_group,std::unique_ptr<elgamal::PublicKey> elgamal_public_key)98 ElGamalEncrypter::ElGamalEncrypter(
99     const ECGroup* ec_group,
100     std::unique_ptr<elgamal::PublicKey> elgamal_public_key)
101     : ec_group_(ec_group), public_key_(std::move(elgamal_public_key)) {}
102 
103 // Encrypts a message m, that has already been mapped onto the curve.
Encrypt(const ECPoint & message) const104 StatusOr<elgamal::Ciphertext> ElGamalEncrypter::Encrypt(
105     const ECPoint& message) const {
106   BigNum r = ec_group_->GeneratePrivateKey();  // generate a random exponent
107   // u = g^r , e = m * y^r .
108   ASSIGN_OR_RETURN(ECPoint u, public_key_->g.Mul(r));
109   ASSIGN_OR_RETURN(ECPoint y_to_r, public_key_->y.Mul(r));
110   ASSIGN_OR_RETURN(ECPoint e, message.Add(y_to_r));
111   return {{std::move(u), std::move(e)}};
112 }
113 
ReRandomize(const elgamal::Ciphertext & elgamal_ciphertext) const114 StatusOr<elgamal::Ciphertext> ElGamalEncrypter::ReRandomize(
115     const elgamal::Ciphertext& elgamal_ciphertext) const {
116   BigNum r = ec_group_->GeneratePrivateKey();  // generate a random exponent
117   // u = old_u * g^r , e = old_e * y^r .
118   ASSIGN_OR_RETURN(ECPoint g_to_r, public_key_->g.Mul(r));
119   ASSIGN_OR_RETURN(ECPoint u, elgamal_ciphertext.u.Add(g_to_r));
120   ASSIGN_OR_RETURN(ECPoint y_to_r, public_key_->y.Mul(r));
121   ASSIGN_OR_RETURN(ECPoint e, elgamal_ciphertext.e.Add(y_to_r));
122   return {{std::move(u), std::move(e)}};
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 // PRIVATE ELGAMAL
127 ////////////////////////////////////////////////////////////////////////////////
128 
ElGamalDecrypter(std::unique_ptr<elgamal::PrivateKey> elgamal_private_key)129 ElGamalDecrypter::ElGamalDecrypter(
130     std::unique_ptr<elgamal::PrivateKey> elgamal_private_key)
131     : private_key_(std::move(elgamal_private_key)) {}
132 
Decrypt(const elgamal::Ciphertext & ciphertext) const133 StatusOr<ECPoint> ElGamalDecrypter::Decrypt(
134     const elgamal::Ciphertext& ciphertext) const {
135   ASSIGN_OR_RETURN(ECPoint u_to_x, ciphertext.u.Mul(private_key_->x));
136   ASSIGN_OR_RETURN(ECPoint u_to_x_inverse, u_to_x.Inverse());
137   ASSIGN_OR_RETURN(ECPoint message, ciphertext.e.Add(u_to_x_inverse));
138   return {std::move(message)};
139 }
140 
PartialDecrypt(const elgamal::Ciphertext & ciphertext) const141 StatusOr<elgamal::Ciphertext> ElGamalDecrypter::PartialDecrypt(
142     const elgamal::Ciphertext& ciphertext) const {
143   ASSIGN_OR_RETURN(ECPoint clone_u, ciphertext.u.Clone());
144   ASSIGN_OR_RETURN(ECPoint dec_e, ElGamalDecrypter::Decrypt(ciphertext));
145   return {{std::move(clone_u), std::move(dec_e)}};
146 }
147 
148 }  // namespace private_join_and_compute
149