Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
mimc.py
Go to the documentation of this file.
1 # Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 #
3 # SPDX-License-Identifier: LGPL-3.0+
4 
5 from zeth.core.constants import MIMC_MT_SEED
6 from zeth.core.merkle_tree import ITreeHash
7 from Crypto.Hash import keccak \
8  # pylint: disable=import-error,no-name-in-module,line-too-long #type: ignore
9 from abc import abstractmethod
10 from typing import List
11 
12 # Reference papers:
13 #
14 # \[AGRRT16]:
15 # "MiMC: Efficient Encryption and Cryptographic Hashing with Minimal
16 # Multiplicative Complexity", Martin Albrecht, Lorenzo Grassi, Christian
17 # Rechberger, Arnab Roy, and Tyge Tiessen, ASIACRYPT 2016,
18 # <https://eprint.iacr.org/2016/492.pdf>
19 #
20 # "One-way compression function"
21 # Section: "Miyaguchi–Preneel"
22 # <https://en.wikipedia.org/wiki/One-way_compression_function#Miyaguchi%E2%80%93Preneel>
23 #
24 # MiMC algorithms are exposed as ITreeHash objects for use in MerkleTree
25 # structures.
26 
27 
29  """
30  Base class of MiMC implementations.
31  """
32  def __init__(
33  self,
34  seed_str: str,
35  prime: int,
36  num_rounds: int):
37  self.seed = _keccak_256(_str_to_bytes(seed_str))
38  self.prime = prime
39  self.num_rounds = num_rounds
40 
41  def encrypt(
42  self,
43  message: int,
44  ek: int) -> int:
45  result = message % self.prime
46  key = ek % self.prime
47  round_constant: int = self.seed
48 
49  # The round constant in round 0 is 0 (see [AGRRT16])
50  result = self.mimc_round(result, key, 0)
51 
52  for _ in range(self.num_rounds - 1):
53  round_constant = _update_round_constant(round_constant)
54  result = self.mimc_round(result, key, round_constant)
55 
56  # Add key to the final result (see [AGRRT16])
57  return (result + key) % self.prime
58 
59  def hash(self, left: bytes, right: bytes) -> bytes:
60  """
61  Apply Miyaguchi-Preneel to the output of the encrypt function.
62  """
63  x = int.from_bytes(left, byteorder='big') % self.prime
64  y = int.from_bytes(right, byteorder='big') % self.prime
65  return self.hash_int(x, y).to_bytes(32, byteorder='big')
66 
67  def hash_int(self, x: int, y: int) -> int:
68  """
69  Similar to hash, but use field elements directly.
70  """
71  assert x < self.prime
72  assert y < self.prime
73  return (self.encrypt(x, y) + x + y) % self.prime
74 
75  @abstractmethod
76  def mimc_round(self, message: int, key: int, rc: int) -> int:
77  pass
78 
79 
81  """
82  Implementation of MiMCBase with exponent 17
83  """
84  def mimc_round(self, message: int, key: int, rc: int) -> int:
85  # May not be optimal to operate on huge numbers (256 * e bits). For
86  # reference, the manual version is below:
87  # a = (message + key + rc) % self.prime
88  # a_2 = (a * a) % self.prime
89  # a_4 = (a_2 * a_2) % self.prime
90  # a_8 = (a_4 * a_4) % self.prime
91  # a_16 = (a_8 * a_8) % self.prime
92  # return (a_16 * a) % self.prime
93  return ((message + key + rc) ** 17) % self.prime
94 
95 
97  """
98  MiMC specialized for Fr in ALT-BN128, using exponent 17 and 65 rounds. See
99  zeth specifications (Section 3.2) for details.
100  """
101  def __init__(self, seed_str: str = MIMC_MT_SEED):
102  super().__init__(
103  seed_str,
104  21888242871839275222246405745257275088548364400416034343698204186575808495617, # noqa
105  # pylint: disable=line-too-long
106  65)
107 
108 
109 class MiMCBLS12_377(MiMC17Base): # pylint: disable=invalid-name
110  """
111  MiMC specialized for Fr in BLS12-377, using exponent 17 and 62 rounds. See
112  zeth specifications (Section 3.2) for details.
113  """
114  def __init__(self, seed_str: str = MIMC_MT_SEED):
115  super().__init__(
116  seed_str,
117  8444461749428370424248824938781546531375899335154063827935233455917409239041, # noqa
118  62)
119 
120 
121 def generate_round_constants(seed_str: str, num_rounds: int) -> List[int]:
122  """
123  Return the first `num_rounds` round constants. Not called directly here,
124  but used to precompute (in particular for the mimc_permutation gadget).
125  """
126  seed = _keccak_256(_str_to_bytes(seed_str))
127  rc = seed
128 
129  rcs = [0]
130  for _ in range(1, num_rounds):
131  rc = _update_round_constant(rc)
132  rcs.append(rc)
133 
134  assert len(rcs) == num_rounds
135  return rcs
136 
137 
138 def get_tree_hash_for_pairing(pairing_name: str) -> ITreeHash:
139  """
140  Select an appropriate hash for a given pairing. Note that these must match
141  the selection logic in `libzeth/circuits/circuit_types.hpp`.
142  """
143  if pairing_name == "alt-bn128":
144  return MiMCAltBN128()
145  if pairing_name == "bls12-377":
146  return MiMCBLS12_377()
147  raise Exception(f"no tree hash for pairing: {pairing_name}")
148 
149 
150 def _str_to_bytes(value: str) -> bytes:
151  return value.encode('ascii')
152 
153 
154 def _int_to_bytes32(value: int) -> bytes:
155  return value.to_bytes(32, 'big')
156 
157 
158 def _keccak_256(data_bytes: bytes) -> int:
159  h = keccak.new(digest_bits=256)
160  h.update(data_bytes)
161  hashed = h.digest()
162  return int.from_bytes(hashed, 'big')
163 
164 
165 def _update_round_constant(rc: int) -> int:
166  return _keccak_256(_int_to_bytes32(rc))
zeth.core.merkle_tree
Definition: merkle_tree.py:1
zeth.core.mimc.generate_round_constants
List[int] generate_round_constants(str seed_str, int num_rounds)
Definition: mimc.py:121
zeth.core.mimc.MiMCBase.num_rounds
num_rounds
Definition: mimc.py:35
zeth.core.mimc.MiMCAltBN128
Definition: mimc.py:96
zeth.core.mimc.MiMCBase
Definition: mimc.py:28
zeth.core.mimc.MiMCBase.mimc_round
int mimc_round(self, int message, int key, int rc)
Definition: mimc.py:76
zeth.core.constants
Definition: constants.py:1
zeth.core.mimc.get_tree_hash_for_pairing
ITreeHash get_tree_hash_for_pairing(str pairing_name)
Definition: mimc.py:138
zeth.core.mimc.MiMCBase.hash
bytes hash(self, bytes left, bytes right)
Definition: mimc.py:59
zeth.core.mimc.MiMCBase.seed
seed
Definition: mimc.py:33
zeth.core.mimc.MiMCBase.__init__
def __init__(self, str seed_str, int prime, int num_rounds)
Definition: mimc.py:32
zeth.core.mimc.MiMCAltBN128.__init__
def __init__(self, str seed_str=MIMC_MT_SEED)
Definition: mimc.py:101
zeth.core.mimc.MiMC17Base
Definition: mimc.py:80
zeth.core.mimc.MiMCBase.encrypt
int encrypt(self, int message, int ek)
Definition: mimc.py:41
zeth.core.mimc.MiMCBLS12_377.__init__
def __init__(self, str seed_str=MIMC_MT_SEED)
Definition: mimc.py:114
zeth.core.mimc.MiMCBase.hash_int
int hash_int(self, int x, int y)
Definition: mimc.py:67
zeth.core.mimc.MiMCBLS12_377
Definition: mimc.py:109
zeth.core.mimc.MiMCBase.prime
prime
Definition: mimc.py:34
zeth.core.merkle_tree.ITreeHash
Definition: merkle_tree.py:17
zeth.core.mimc.MiMC17Base.mimc_round
int mimc_round(self, int message, int key, int rc)
Definition: mimc.py:84