Transaction Details
Transaction Hash:
45b66fd17bcef7bf299268bcccd772ecd16c36c0ece720d284d55e24c365341c
From:
0xe1288759446298f250c3bce5616706d25525ba7f
Transaction Data
{'p': 'zentest3', 'f': 'function_snippet', 'a': ['# Paillier helpers + privacy transfer flow (ZIP23)\n\ndef _egcd(a, b):\n x0, y0 = 1, 0\n x1, y1 = 0, 1\n while b != 0:\n q = a // b\n a, b = b, a % b\n x0, x1 = x1, x0 - q * x1\n y0, y1 = y1, y0 - q * y1\n return a, x0, y0\n\ndef _modinv(a, n):\n g, x, _ = _egcd(a, n)\n assert g == 1\n return x % n\n\ndef _homomorphic_add(pub, c1, c2):\n n = pub\n n2 = n * n\n return (c1 * c2) % n2\n\ndef _homomorphic_sub(pub, c1, c2):\n n = pub\n n2 = n * n\n inv = _modinv(c2, n2)\n return (c1 * inv) % n2\n\n\n# Elliptic Curve parameters for secp256k1\nP = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\nA = 0\nB = 7\nGx = 55066263022277343669578718895168534326250603453777594175500187360389116729240\nGy = 32670510020758816978083085130507043184471273380659243275938904335757337482424\nG = (Gx, Gy)\nN = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\n\ndef _inverse_mod(k, p):\n if k == 0:\n raise\n return pow(k, p - 2, p)\n\ndef _is_on_curve(point):\n if point is None:\n return True\n x, y = point\n return (y * y - (x * x * x + A * x + B)) % P == 0\n\ndef _point_add(point1, point2):\n if point1 is None:\n return point2\n if point2 is None:\n return point1\n x1, y1 = point1\n x2, y2 = point2\n if x1 == x2 and y1 != y2:\n return None\n if x1 == x2:\n m = (3 * x1 * x1 + A) * _inverse_mod(2 * y1, P)\n else:\n m = (y2 - y1) * _inverse_mod(x2 - x1, P)\n m %= P\n x3 = (m * m - x1 - x2) % P\n y3 = (m * (x1 - x3) - y1) % P\n return (x3, y3)\n\ndef _scalar_mult(k, point):\n result = None\n addend = point\n while k:\n if k & 1:\n result = _point_add(result, addend)\n addend = _point_add(addend, addend)\n k >>= 1\n return result\n\ndef _ecdsa_verify(msg_hash_hex, signature_hex, public_key_hex):\n assert msg_hash_hex.startswith(\'0x\')\n assert signature_hex.startswith(\'0x\')\n assert public_key_hex.startswith(\'0x\')\n r = int(signature_hex[2:66], 16)\n s = int(signature_hex[66:130], 16)\n if not (1 <= r < N and 1 <= s < N):\n return False\n point = (int(public_key_hex[2:66], 16), int(public_key_hex[66:], 16))\n e = int(msg_hash_hex[2:], 16)\n w = _inverse_mod(s, N)\n u1 = (e * w) % N\n u2 = (r * w) % N\n q = _point_add(_scalar_mult(u1, G), _scalar_mult(u2, point))\n if q is None:\n return False\n x, y = q\n return r == x % N\n\ndef _ecdsa_recover(msg_hash_hex, signature_hex):\n assert msg_hash_hex.startswith(\'0x\')\n assert signature_hex.startswith(\'0x\')\n r = int(signature_hex[2:66], 16)\n s = int(signature_hex[66:130], 16)\n z = int(msg_hash_hex[2:], 16)\n\n if len(signature_hex[2:]) == 130:\n v = int(signature_hex[130:], 16)\n if v >= 27:\n recovery_id = v - 27\n else:\n recovery_id = v\n recovery_ids = [recovery_id]\n else:\n recovery_ids = [0, 1]\n\n for recovery_id in recovery_ids:\n for j in range(2):\n x = r + j * N\n if x >= P:\n continue\n\n y_squared = (pow(x, 3, P) + A * x + B) % P\n y = pow(y_squared, (P + 1) // 4, P)\n\n if y % 2 != recovery_id:\n y = P - y\n\n point = (x, y)\n if not _is_on_curve(point):\n continue\n\n r_inv = _inverse_mod(r, N)\n u1 = (-z * r_inv) % N\n u2 = (s * r_inv) % N\n\n q = _point_add(_scalar_mult(u1, G), _scalar_mult(u2, point))\n\n if q is None:\n continue\n\n public_key_hex = f"0x{q[0]:064x}{q[1]:064x}"\n if _ecdsa_verify(msg_hash_hex, signature_hex, public_key_hex):\n return public_key_hex\n\n return None\n\ndef _pubkey_to_address(public_key_hex):\n public_key_bytes = bytes.fromhex(public_key_hex[2:])\n address_bytes = keccak(public_key_bytes)[-20:]\n return \'0x\' + address_bytes.hex()\n\ndef _message_hash(payload):\n payload_hash = keccak(text=payload)\n prefix = b"\\x19Ethereum Signed Message:\\n32"\n return keccak(prefix + payload_hash)\n\ndef _addr_recover(msg, signature_hex):\n if not signature_hex.startswith(\'0x\'):\n signature_hex = \'0x\' + signature_hex\n msg_hash = _message_hash(msg)\n msg_hash_hex = msg_hash.hex()\n if not msg_hash_hex.startswith(\'0x\'):\n msg_hash_hex = \'0x\' + msg_hash_hex\n public_key_hex = _ecdsa_recover(msg_hash_hex, signature_hex)\n if not public_key_hex:\n return False\n recovered = _pubkey_to_address(public_key_hex)\n return recovered.lower()\n\ndef _resolve_account(addr):\n addr = addr.lower()\n assert len(addr) <= 42\n if len(addr) == 42:\n assert addr.startswith(\'0x\')\n assert set(addr[2:]) <= set(string.digits + \'abcdef\')\n else:\n assert len(addr) > 4\n\n if len(addr) == 42:\n return handle_lookup(addr)\n return addr\n\ndef _check_tick(tick):\n assert type(tick) is str\n assert len(tick) > 0 and len(tick) < 42\n assert tick[0] in string.ascii_uppercase\n assert set(tick) <= set(string.ascii_uppercase + string.digits + \'_\')\n\n\ndef _get_pubkey(privacy_tick):\n pub, _ = get(privacy_tick, \'privacy_pub\', None)\n if pub is None:\n return None\n return int(pub)\n\n\ndef privacy_init(info, args):\n assert args[\'f\'] == \'privacy_init\'\n\n tick = args[\'a\'][0]\n _check_tick(tick)\n privacy_tick = args[\'a\'][1]\n _check_tick(privacy_tick)\n provider_addr = args[\'a\'][2]\n paillier_pub = int(args[\'a\'][3])\n\n sender = info[\'sender\']\n\n existing_provider, _ = get(privacy_tick, \'privacy_provider\', None)\n assert existing_provider is None, "Provider already initialized"\n\n put(provider_addr, privacy_tick, \'tick\', tick)\n put(provider_addr, privacy_tick, \'privacy_provider\', provider_addr)\n put(provider_addr, privacy_tick, \'privacy_pub\', int(paillier_pub))\n\n\ndef privacy_update(info, args):\n assert args[\'f\'] == \'privacy_update\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n owner, _ = get(\'asset\', \'owner\', None, privacy_tick)\n assert owner.lower() == info[\'sender\'].lower(), f"Only owner can update {privacy_tick}"\n\n provider_addr = args[\'a\'][1]\n assert provider_addr.startswith(\'0x\') and len(provider_addr) == 42\n put(provider_addr, privacy_tick, \'privacy_provider\', provider_addr.lower())\n\n paillier_pub = int(args[\'a\'][2])\n put(provider_addr, privacy_tick, \'privacy_pub\', int(paillier_pub))\n event(\'PrivacyUpdate\', [privacy_tick, provider_addr])\n\n\ndef privacy_deposit(info, args):\n assert args[\'f\'] == \'privacy_deposit\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n functions, _ = get(\'asset\', \'functions\', [], tick)\n assert args[\'f\'] in functions\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n addr = handle_lookup(sender)\n\n amount = int(args[\'a\'][1])\n assert amount >= 0\n\n amount_cipher = int(args[\'a\'][2])\n assert amount_cipher >= 0\n\n nonce = int(args[\'a\'][3])\n assert nonce >= 0\n\n signature_hex = args[\'a\'][4]\n assert signature_hex.startswith(\'0x\')\n\n stored_nonce, _ = get(privacy_tick, \'privacy_nonce\', 0, sender)\n assert nonce == stored_nonce + 1\n put(sender, privacy_tick, \'privacy_nonce\', nonce, sender)\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n msg_to_sign = f\'{privacy_tick},privacy_deposit,{sender},{nonce},{amount},{amount_cipher}\'\n\n recovered_addr = _addr_recover(msg_to_sign, signature_hex)\n assert provider_addr.lower() == recovered_addr, "Invalid signature"\n\n total_supply, _ = get(privacy_tick, \'total_supply\', 0)\n put(provider_addr, privacy_tick, \'total_supply\', int(total_supply) + amount)\n\n balance, _ = get(tick, \'balance\', 0, f\'{sender}\')\n assert balance >= amount\n balance_updated = balance - amount\n put(addr, tick, \'balance\', balance_updated, addr)\n\n pool_balance, _ = get(tick, \'balance\', 0, privacy_tick)\n put(privacy_tick, tick, \'balance\', int(pool_balance) + amount, privacy_tick)\n\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, addr)\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, sender)\n event(\'PrivacyDeposit\', [privacy_tick, addr, amount, amount_cipher, nonce])\n\n\ndef privacy_withdraw(info, args):\n assert args[\'f\'] == \'privacy_withdraw\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n amount = int(args[\'a\'][1])\n assert amount > 0\n amount_cipher = int(args[\'a\'][2])\n assert amount_cipher > 0\n old_balance_cipher = int(args[\'a\'][3])\n assert old_balance_cipher > 0\n nonce = int(args[\'a\'][4]) \n signature = args[\'a\'][5]\n\n sender = info[\'sender\']\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n assert provider_addr is not None, "Provider not initialized"\n\n stored_nonce, _ = get(privacy_tick,\'privacy_nonce\', 0, sender)\n assert nonce == int(stored_nonce) + 1, "Invalid nonce"\n\n msg = f"{privacy_tick},privacy_withdraw,{sender},{nonce},{amount},{amount_cipher},{old_balance_cipher}"\n recovered_addr = _addr_recover(msg, signature)\n assert recovered_addr == provider_addr.lower(), "Invalid signature"\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n stored_balance, _ = get(privacy_tick, \'privacy_balance\', 1, sender)\n assert int(stored_balance) == old_balance_cipher, "State mismatch"\n\n total_supply, _ = get(privacy_tick, \'total_supply\', 0)\n new_total = int(total_supply) - amount\n assert new_total >= 0, "Insufficent total supply"\n\n new_balance_cipher = _homomorphic_sub(pub, int(stored_balance), amount_cipher)\n\n put(sender, privacy_tick, \'privacy_balance\', new_balance_cipher, sender)\n put(sender, privacy_tick, \'privacy_nonce\', nonce, sender)\n put(provider_addr, privacy_tick, \'total_supply\', new_total)\n\n pool_balance, _ = get(tick, \'balance\', 0, privacy_tick)\n put(privacy_tick, tick, \'balance\', int(pool_balance) - amount, privacy_tick)\n\n user_balance, _ = get(tick, \'balance\', 0, sender)\n put(sender, tick, \'balance\', int(user_balance) + amount, sender)\n\n event(\'PrivacyWithdraw\', [sender, amount, new_balance_cipher, nonce])\n\n\ndef privacy_transfer(info,args):\n assert args[\'f\'] == \'privacy_transfer\'\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n to_addr = args[\'a\'][1].lower()\n amount_cipher = int(args[\'a\'][2])\n assert amount_cipher > 0\n\n nonce = int(args[\'a\'][3])\n assert nonce > 0\n signature = args[\'a\'][4]\n assert signature.startswith(\'0x\')\n\n sender = info[\'sender\']\n assert sender != to_addr, "Self-transfer not allowed"\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n assert provider_addr is not None, "Provider not initialized"\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n msg = f"{privacy_tick},privacy_transfer,{sender},{to_addr},{nonce},{amount_cipher}"\n recovered_addr = _addr_recover(msg, signature)\n assert recovered_addr == provider_addr.lower(), "Invalid provider signature"\n\n current_sender_bal, _ = get(privacy_tick, \'privacy_balance\', 1, sender)\n current_receiver_bal, _ = get(privacy_tick, \'privacy_balance\', 1, to_addr)\n\n stored_nonce, _ = get(privacy_tick, \'privacy_nonce\', 0, sender)\n assert nonce == int(stored_nonce) + 1, "Invalid nonce"\n\n new_sender_bal = _homomorphic_sub(pub, int(current_sender_bal), amount_cipher)\n new_receiver_bal = _homomorphic_add(pub, int(current_receiver_bal), amount_cipher)\n\n put(sender, privacy_tick, \'privacy_balance\', new_sender_bal, sender)\n put(sender, privacy_tick, \'privacy_nonce\', nonce, sender)\n put(to_addr, privacy_tick, \'privacy_balance\', new_receiver_bal, to_addr)\n\n event(\'PrivacyTransfer\', [sender, to_addr, amount_cipher, nonce])\n\n']}
Events
[['function_snippet', 'NewFunctionSnippet', '2e3f7fcf48f9c178aa5520c60d147ef15c69272048a10138f6fee7db4741981b']]