Transaction Details



Transaction Hash:
45b66fd17bcef7bf299268bcccd772ecd16c36c0ece720d284d55e24c365341c
Transaction Index:
1
From:
0xe1288759446298f250c3bce5616706d25525ba7f
Block Height:
38954859

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']]