Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
utils.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 # Copyright (c) 2015-2022 Clearmatics Technologies Ltd
4 #
5 # SPDX-License-Identifier: LGPL-3.0+
6 
7 # Parse the arguments given to the script
8 
9 from __future__ import annotations
10 from . import constants
11 from . import errors
12 
13 import argparse
14 import sys
15 import os
16 from os.path import join, dirname, normpath, exists
17 import eth_abi
18 import eth_keys # type: ignore
19 from web3 import Web3, HTTPProvider # type: ignore
20 from typing import Sequence, List, Tuple, Union, Iterable, Any, Optional, cast
21 
22 # Some Ethereum node implementations can cause a timeout if the contract
23 # execution takes too long. We expect the contract to complete in under 30s on
24 # most machines, but allow 1 min.
25 WEB3_HTTP_PROVIDER_TIMEOUT_SEC = 60
26 
27 
29  url: str,
30  certificate: Optional[str] = None,
31  insecure: bool = False) -> Any:
32  """
33  Create a Web3 context from an http URL.
34  """
35  if certificate and not exists(certificate):
36  raise FileNotFoundError(f"certificate file not found: {certificate}")
37  assert not certificate or exists(certificate)
38  request_verify: Union[str, bool, None] = False if insecure else certificate
39  request_kwargs = {
40  'timeout': WEB3_HTTP_PROVIDER_TIMEOUT_SEC,
41  'verify': request_verify,
42  }
43  return Web3(HTTPProvider(url, request_kwargs=request_kwargs))
44 
45 
46 class EtherValue:
47  """
48  Representation of some amount of Ether (or any token) in terms of Wei.
49  Disambiguates Ether values from other units such as zeth_units.
50  """
51  def __init__(self, val: Union[str, int, float], units: str = 'ether'):
52  self.wei = Web3.toWei(val, units)
53 
54  def __str__(self) -> str:
55  return str(self.wei)
56 
57  def __add__(self, other: EtherValue) -> EtherValue:
58  return EtherValue(self.wei + other.wei, 'wei')
59 
60  def __sub__(self, other: EtherValue) -> EtherValue:
61  return EtherValue(self.wei - other.wei, 'wei')
62 
63  def __eq__(self, other: Any) -> bool:
64  if not isinstance(other, EtherValue):
65  return False
66  return self.wei == other.wei
67 
68  def __ne__(self, other: Any) -> bool:
69  return not self.__eq__(other)
70 
71  def __lt__(self, other: EtherValue) -> bool:
72  return self.wei < other.wei
73 
74  def __le__(self, other: EtherValue) -> bool:
75  return self.wei <= other.wei
76 
77  def __gt__(self, other: EtherValue) -> bool:
78  return self.wei > other.wei
79 
80  def __ge__(self, other: EtherValue) -> bool:
81  return self.wei >= other.wei
82 
83  def __bool__(self) -> bool:
84  return int(self.wei) != 0
85 
86  def ether(self) -> str:
87  return str(Web3.fromWei(self.wei, 'ether'))
88 
89 
90 def encode_single(type_name: str, data: Any) -> bytes:
91  """
92  Typed wrapper around eth_abi.encode_single
93  """
94  return eth_abi.encode_single(type_name, data) # type: ignore
95 
96 
97 def encode_abi(type_names: List[str], data: List[Any]) -> bytes:
98  """
99  Typed wrapper around eth_abi.encode_abi
100  """
101  return eth_abi.encode_abi(type_names, data) # type: ignore
102 
103 
104 def eth_address_to_bytes(eth_addr: str) -> bytes:
105  """
106  Binary encoding of ethereum address to 20 bytes
107  """
108  # Strip the leading '0x' and hex-decode.
109  assert len(eth_addr) == 42
110  assert eth_addr.startswith("0x")
111  return bytes.fromhex(eth_addr[2:])
112 
113 
114 def eth_address_to_bytes32(eth_addr: str) -> bytes:
115  """
116  Binary encoding of ethereum address to 32 bytes
117  """
118  return extend_32bytes(eth_address_to_bytes(eth_addr))
119 
120 
121 def eth_uint256_to_int(eth_uint256: str) -> int:
122  assert isinstance(eth_uint256, str)
123  assert eth_uint256.startswith("0x")
124  return int.from_bytes(
125  bytes.fromhex(hex_extend_32bytes(eth_uint256[2:])),
126  byteorder='big')
127 
128 
129 def eth_address_from_private_key(eth_private_key: bytes) -> str:
130  pk = eth_keys.keys.PrivateKey(eth_private_key)
131  return pk.public_key.to_address()
132 
133 
134 def int_and_bytelen_from_hex(value_hex: str) -> Tuple[int, int]:
135  """
136  Decode prefixed / non-prefixed hex string and extract the length in bytes
137  as well as the value.
138  """
139  assert len(value_hex) % 2 == 0
140  if value_hex.startswith("0x"):
141  num_bytes = int((len(value_hex) - 2) / 2)
142  else:
143  num_bytes = int(len(value_hex) / 2)
144  return (int(value_hex, 16), num_bytes)
145 
146 
147 def int_to_hex(value: int, num_bytes: int) -> str:
148  """
149  Create prefixed hex string enforcing a specific byte-length.
150  """
151  return "0x" + value.to_bytes(num_bytes, byteorder='big').hex()
152 
153 
154 def int64_to_bytes(number: int) -> bytes:
155  return number.to_bytes(8, 'big')
156 
157 
158 def int64_to_hex(number: int) -> str:
159  return int64_to_bytes(number).hex()
160 
161 
162 def hex_digest_to_binary_string(digest: str) -> str:
163  if len(digest) % 2 == 1:
164  digest = "0" + digest
165  return "".join(["{0:04b}".format(int(c, 16)) for c in digest])
166 
167 
168 def digest_to_binary_string(digest: bytes) -> str:
169  return "".join(["{0:08b}".format(b) for b in digest])
170 
171 
172 def hex_to_uint256_list(hex_str: str) -> Iterable[int]:
173  """
174  Given a hex string of arbitrary size, split into uint256 ints, left padding
175  with 0s.
176  """
177  if hex_str.startswith("0x"):
178  hex_str = hex_str[2:]
179  assert len(hex_str) % 2 == 0
180  start_idx = 0
181  next_idx = len(hex_str) - int((len(hex_str) - 1) / 64) * 64
182  while next_idx <= len(hex_str):
183  sub_str = hex_str[start_idx:next_idx]
184  yield int(sub_str, 16)
185  start_idx = next_idx
186  next_idx = next_idx + 64
187 
188 
190  elements: Sequence[Union[str, List[str]]]) -> List[int]:
191  """
192  Given an array of hex strings, return an array of int values by converting
193  each hex string to evm uint256 words, and flattening the final list.
194  """
195  # In reality, we need to cope with lists of lists, to handle all
196  # field extension degrees for all curve coordinate types.
197  # TODO: Create a new type to describe this safely.
198  flat_elements = string_list_flatten(elements)
199  return [i for hex_str in flat_elements for i in hex_to_uint256_list(hex_str)]
200 
201 
202 def extend_32bytes(value: bytes) -> bytes:
203  """
204  Pad value on the left with zeros, to make 32 bytes.
205  """
206  assert len(value) <= 32
207  return bytes(32-len(value)) + value
208 
209 
210 def hex_extend_32bytes(element: str) -> str:
211  """
212  Extend a hex string to represent 32 bytes
213  """
214  res = str(element)
215  if len(res) % 2 != 0:
216  res = "0" + res
217  return extend_32bytes(bytes.fromhex(res)).hex()
218 
219 
220 def to_zeth_units(value: EtherValue) -> int:
221  """
222  Convert a quantity of ether / token to Zeth units
223  """
224  return int(value.wei / constants.ZETH_PUBLIC_UNIT_VALUE)
225 
226 
227 def from_zeth_units(zeth_units: int) -> EtherValue:
228  """
229  Convert a quantity of ether / token to Zeth units
230  """
231  return EtherValue(zeth_units * constants.ZETH_PUBLIC_UNIT_VALUE, "wei")
232 
233 
234 def parse_zksnark_arg() -> str:
235  """
236  Parse the zksnark argument and return its value
237  """
238  parser = argparse.ArgumentParser(
239  description="Testing Zeth transactions using the specified zkSNARK " +
240  "('GROTH16' or 'PGHR13').\nNote that the zkSNARK must match the one " +
241  "used on the prover server.")
242  parser.add_argument("zksnark", help="Set the zkSNARK to use")
243  args = parser.parse_args()
244  if args.zksnark not in constants.VALID_ZKSNARKS:
245  return sys.exit(errors.SNARK_NOT_SUPPORTED)
246  return args.zksnark
247 
248 
249 def get_zeth_dir() -> str:
250  return os.environ.get(
251  'ZETH',
252  normpath(join(dirname(__file__), "..", "..", "..")))
253 
254 
255 def get_contracts_dir() -> str:
256  return os.environ.get(
257  'ZETH_CONTRACTS_DIR',
258  join(get_zeth_dir(), "zeth_contracts", "contracts"))
259 
260 
261 def string_list_flatten(str_list: Sequence[Union[str, List[str]]]) -> List[str]:
262  """
263  Flatten a list containing strings or lists of strings.
264  """
265  if any(isinstance(el, (list, tuple)) for el in str_list):
266  strs: List[str] = []
267  for el in str_list:
268  if isinstance(el, (list, tuple)):
269  strs.extend(el)
270  else:
271  strs.append(cast(str, el))
272  return strs
273 
274  return cast(List[str], str_list)
275 
276 
277 def message_to_bytes(message_list: Any) -> bytes:
278  # message_list: Union[List[str], List[Union[int, str, List[str]]]]) -> bytes:
279  """
280  Encode a list of variables, or list of lists of variables into a byte
281  vector
282  """
283 
284  messages = string_list_flatten(message_list)
285 
286  data_bytes = bytearray()
287  for m in messages:
288  # For each element
289  m_hex = m
290 
291  # Convert it into a hex
292  if isinstance(m, int):
293  m_hex = "{0:0>4X}".format(m)
294  elif isinstance(m, str) and (m[1] == "x"):
295  m_hex = m[2:]
296 
297  # [SANITY CHECK] Make sure the hex is 32 byte long
298  m_hex = hex_extend_32bytes(m_hex)
299 
300  # Encode the hex into a byte array and append it to result
301  data_bytes += encode_single("bytes32", bytes.fromhex(m_hex))
302 
303  return data_bytes
304 
305 
306 def short_commitment(cm: bytes) -> str:
307  """
308  Summary of the commitment value, in some standard format.
309  """
310  return cm[0:4].hex()
zeth.core.utils.hex_list_to_uint256_list
List[int] hex_list_to_uint256_list(Sequence[Union[str, List[str]]] elements)
Definition: utils.py:189
zeth.core.utils.hex_extend_32bytes
str hex_extend_32bytes(str element)
Definition: utils.py:210
test_commands.mock.str
str
Definition: mock.py:18
zeth.core.utils.EtherValue.__init__
def __init__(self, Union[str, int, float] val, str units='ether')
Definition: utils.py:51
zeth.core.utils.EtherValue.__lt__
bool __lt__(self, EtherValue other)
Definition: utils.py:71
zeth.core.utils.eth_uint256_to_int
int eth_uint256_to_int(str eth_uint256)
Definition: utils.py:121
zeth.cli.zeth_deploy.int
int
Definition: zeth_deploy.py:27
zeth.core.utils.EtherValue.__str__
str __str__(self)
Definition: utils.py:54
zeth.core.utils.int64_to_bytes
bytes int64_to_bytes(int number)
Definition: utils.py:154
zeth.core.utils.open_web3
Any open_web3(str url, Optional[str] certificate=None, bool insecure=False)
Definition: utils.py:28
zeth.core.utils.string_list_flatten
List[str] string_list_flatten(Sequence[Union[str, List[str]]] str_list)
Definition: utils.py:261
zeth.core.utils.EtherValue.__ge__
bool __ge__(self, EtherValue other)
Definition: utils.py:80
zeth.core.utils.EtherValue.ether
str ether(self)
Definition: utils.py:86
zeth.core.utils.get_zeth_dir
str get_zeth_dir()
Definition: utils.py:249
zeth.core.utils.EtherValue.wei
wei
Definition: utils.py:52
zeth.core.utils.int_to_hex
str int_to_hex(int value, int num_bytes)
Definition: utils.py:147
zeth.core.utils.int_and_bytelen_from_hex
Tuple[int, int] int_and_bytelen_from_hex(str value_hex)
Definition: utils.py:134
zeth.core.encryption.bytes
bytes
Definition: encryption.py:87
zeth.core.utils.encode_single
bytes encode_single(str type_name, Any data)
Definition: utils.py:90
zeth.core.utils.EtherValue.__bool__
bool __bool__(self)
Definition: utils.py:83
zeth.core.utils.encode_abi
bytes encode_abi(List[str] type_names, List[Any] data)
Definition: utils.py:97
zeth.core.utils.eth_address_to_bytes
bytes eth_address_to_bytes(str eth_addr)
Definition: utils.py:104
zeth.core.utils.EtherValue.__eq__
bool __eq__(self, Any other)
Definition: utils.py:63
zeth.core.utils.EtherValue.__sub__
EtherValue __sub__(self, EtherValue other)
Definition: utils.py:60
zeth.core.utils.extend_32bytes
bytes extend_32bytes(bytes value)
Definition: utils.py:202
zeth.core.utils.eth_address_to_bytes32
bytes eth_address_to_bytes32(str eth_addr)
Definition: utils.py:114
zeth.core.utils.EtherValue.__le__
bool __le__(self, EtherValue other)
Definition: utils.py:74
zeth.core.utils.EtherValue.__ne__
bool __ne__(self, Any other)
Definition: utils.py:68
zeth.core.utils.digest_to_binary_string
str digest_to_binary_string(bytes digest)
Definition: utils.py:168
zeth.core.utils.short_commitment
str short_commitment(bytes cm)
Definition: utils.py:306
zeth.core.utils.to_zeth_units
int to_zeth_units(EtherValue value)
Definition: utils.py:220
zeth.core.utils.EtherValue.__gt__
bool __gt__(self, EtherValue other)
Definition: utils.py:77
zeth.core.utils.from_zeth_units
EtherValue from_zeth_units(int zeth_units)
Definition: utils.py:227
zeth.core.utils.EtherValue
Definition: utils.py:46
zeth.core.utils.message_to_bytes
bytes message_to_bytes(Any message_list)
Definition: utils.py:277
zeth.core.utils.hex_digest_to_binary_string
str hex_digest_to_binary_string(str digest)
Definition: utils.py:162
zeth.core.utils.get_contracts_dir
str get_contracts_dir()
Definition: utils.py:255
zeth.core.utils.int64_to_hex
str int64_to_hex(int number)
Definition: utils.py:158
zeth.core.utils.parse_zksnark_arg
str parse_zksnark_arg()
Definition: utils.py:234
zeth.core.utils.EtherValue.__add__
EtherValue __add__(self, EtherValue other)
Definition: utils.py:57
zeth.core.utils.hex_to_uint256_list
Iterable[int] hex_to_uint256_list(str hex_str)
Definition: utils.py:172
zeth.core.utils.eth_address_from_private_key
str eth_address_from_private_key(bytes eth_private_key)
Definition: utils.py:129