xref: /aosp_15_r20/external/private-join-and-compute/private_join_and_compute/py/ciphers/ec_cipher.py (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
1# Copyright 2019 Google LLC.
2#
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"""EC based commutative cipher."""
16
17from typing import Optional
18
19from private_join_and_compute.py.crypto_util import elliptic_curve
20from private_join_and_compute.py.crypto_util import supported_hashes
21
22NID_secp224r1 = 713  # pylint: disable=invalid-name
23DEFAULT_CURVE_ID = NID_secp224r1
24POINT_CONVERSION_COMPRESSED = 2
25
26
27class EcCipher(object):
28  """A commutative cipher based on Elliptic Curves."""
29
30  # key is an address.
31  def __init__(
32      self,
33      curve_id: int = DEFAULT_CURVE_ID,
34      private_key_bytes: Optional[bytes] = None,
35      hash_type: Optional[supported_hashes.HashType] = None,
36  ) -> None:
37    """Generate a new EC key pair, if the key is not passed as a parameter.
38
39    The private key is a random value and the private point is the result of
40    performing a scalar point multiplication of that value with the curve's
41    base point.
42
43    Args:
44      curve_id: the id of the curve to use, given as an int value.
45      private_key_bytes: an ec key in bytes, if the key has already been
46        generated.
47      hash_type: the hash to use in order to map a string to the elliptic curve.
48
49    Raises:
50      TypeError: If curve_id is not an int.
51      Exception: If the key could not be generated.
52    """
53    self._ec_key = elliptic_curve.ECKey(curve_id, private_key_bytes, hash_type)
54
55  def Encrypt(self, id_bytes: bytes) -> bytes:
56    """Hashes the client id to a point on the curve.
57
58    It then encrypts the point by multiplying it with the private key.
59
60    Args:
61      id_bytes: a client id encoded as a string/byte value.
62
63    Returns:
64      the compressed encoded EC Point in bytes.
65
66    Raises:
67      TypeError: If id_bytes is not a str type.
68    """
69    ec_point = self._ec_key.elliptic_curve.GetPointByHashingToCurve(id_bytes)
70    return self.EncryptPoint(ec_point)
71
72  def EncryptPoint(self, ec_point) -> bytes:
73    """Encrypts a point on the curve.
74
75    Args:
76      ec_point: the point to encrypt.
77
78    Returns:
79      the compressed encoded encrypted point in bytes
80    """
81    ec_point *= self._ec_key.priv_key_bn
82    return ec_point.GetAsBytes()
83
84  def ReEncrypt(self, enc_id_bytes: bytes) -> bytes:
85    """Re-encrypts the id by multiplying with the private key.
86
87    Args:
88      enc_id_bytes: an encrypted client id as a bytes value.
89
90    Returns:
91      the compressed encoded re-encrypted EC Point in bytes.
92
93    Raises:
94      TypeError: If enc_id_bytes id is not a str type.
95    """
96    ec_point = self._ec_key.elliptic_curve.GetPointFromBytes(enc_id_bytes)
97    return self.EncryptPoint(ec_point)
98
99  @property
100  def ec_key(self):
101    return self._ec_key
102
103  @property
104  def elliptic_curve(self):
105    return self._ec_key.elliptic_curve
106
107  def DecryptReEncryptedId(self, reenc_id_bytes: bytes) -> bytes:
108    """Decrypts a reencrypted id to its encrypted id form.
109
110    Assuming reenc_id_bytes=E_k1(E_k2(m)) where E(.) is the ec_cipher and k1/k2
111    are private keys. This function with decryption key, k1', returns E_k2(m) or
112    with decryption key, k2', E_k1(m). Essentially this removes one layer of
113    encryption from the reenc_id_bytes.
114
115    This function *cannot* be applied to encrypted ids as the return value would
116    be the message one-way hashed to a point on the curve.
117
118    Args:
119      reenc_id_bytes: a reencrypted client id, encoded with a key and then
120        reencoded with another key.
121
122    Returns:
123      An encoded id in bytes.
124    """
125    ec_point = self._ec_key.elliptic_curve.GetPointFromBytes(reenc_id_bytes)
126    ec_point *= self._ec_key.decrypt_key_bignum
127    return ec_point.GetAsBytes()
128