rustyrussell / secp256k1-py

Python FFI bindings for libsecp256k1 (maintained)
MIT License
57 stars 13 forks source link

Recommended way to negate points #10

Open AdamISZ opened 2 years ago

AdamISZ commented 2 years ago

I know that the underlying secp256k1 library exposes a pubkey_negate :

https://github.com/bitcoin-core/secp256k1/blob/6f6cab9989a4d3f4a28e3cdbfacc4e3e1e55c843/include/secp256k1.h#L668

but at first thought, it's not that surprising that this isn't exposed in this binding, since we have the most fundamental operations: combine (add pubkeys together) and tweak_mul, tweak_add.

Still, it leaves me a little uncertain what the best way to do -P is. In the now "legacy" compressed encoding we can flip 02/03 starting byte. That feels like an icky way to do it (even if it wasn't the case that we're now tending to use the new Schnorr style 32 byte pubkeys); mathematical operations on keys shouldn't be executed by manipulating their encodings.

Another obvious thought is: use scalar mult (so tweak_mul) with the value "-1", but that is N-1 where N is the group order and it also feels very bad to be introducing that kind of calculation outside the library/binding.

Am I missing an obvious way to do it?

moonsettler commented 1 year ago

Ran into the same issue, negation, subtraction was easy enough. https://replit.com/@moonsettler/BlindSchnorrMuSig#secp.py

from secp256k1 import PrivateKey, PublicKey

class PublicKeyExt(PublicKey):

    def __neg__(self):
        serialized = self.serialize()
        first_byte, remainder = serialized[:1], serialized[1:]
        # flip odd/even byte
        first_byte = {b"\x03": b"\x02", b"\x02": b"\x03"}[first_byte]
        return PublicKey(first_byte + remainder, raw=True)

 PublicKey.__neg__ = PublicKeyExt.__neg__

 class PrivateKeyExt(PrivateKey):

    def __neg__(self):
      order = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 #order of secp256k1 group
      neg_num=_int_to_bytes(order-_bytes_to_int(self.private_key, 'big'), 32, 'big')
      return PrivateKey(neg_num, raw=True)

 PrivateKey.__neg__ = PrivateKeyExt.__neg__

Now I need the inverse modulo (secp256k1_scalar_inverse?)...