21-DOT-DEV / swift-secp256k1

Elliptic Curve, Schnorr, and ZKP for Bitcoin. Supports iOS macOS tvOS watchOS visionOS + Linux.
MIT License
112 stars 54 forks source link

How to use secp256k1_ec_pubkey_combine #397

Closed POLAX7 closed 1 year ago

POLAX7 commented 1 year ago

How to use secp256k1_ec_pubkey_combine ? I'd like to use this function from secp256k1 But there is no interface from this library. Would you like to show that how to use it? Thank you.

csjones commented 1 year ago

Hey @POLAX7 👋

The function binding for secp256k1_ec_pubkey_combine is available. The package doesn't offer a Swift API yet, what use case do you want secp256k1_ec_pubkey_combine for? Any specifics would be helpful towards adding it.

Quick and dirty way to use secp256k1_ec_pubkey_combine using this package:

func combine(_ pubkeys: [PublicKey]) {
    let context = secp256k1.Context.rawRepresentation
    var publicKey = secp256k1_pubkey()
    var keys = pubkeys.map {
        var newPubKey = secp256k1_pubkey()
        $0.rawRepresentation.copyToUnsafeMutableBytes(of: &newPubKey.data)
        let pointerKey: UnsafePointer<secp256k1_pubkey>? = withUnsafePointer(to: &newPubKey) { $0 }
        return pointerKey
    }

    secp256k1_ec_pubkey_combine(context, &publicKey, &keys, pubkeys.count)
}
POLAX7 commented 1 year ago

Thank you for your replying. I tried your solution. But Type 'secp256k1.Context' has no member 'rawRepresentation' And what swift type should I return from secp256k1_ec_pubkey_combine ? convert it from int to hex data?

csjones commented 1 year ago

Do you have an example of what you want to do exactly? I can’t help much without a better understanding of your goal.

POLAX7 commented 1 year ago

I just want to calculate with secp256k1_ec_pubkey_combine for schnorr. 'secp256k1.Context' has no member 'rawRepresentation' in your code secp256k1.Context.rawRepresentation Would you like to tell me what should I put in context? And is the result of secp256k1_ec_pubkey_combine is &publicKey ? the return value of secp256k1_ec_pubkey_combine is present succeed or failed ? Is my understanding correct?

csjones commented 1 year ago

Haven't been able to reproduce your error. I imported the package into a new target and still able to use secp256k1.Context.rawRepresentation directly. I'm still not clear what you're goal is for using secp256k1_ec_pubkey_combine with Schnorr. Is there a specific BIP you are trying to implement? Or are you trying to create a Schnorr multisig? Any links to references would be helpful to understand.

Screenshot 2023-07-19 at 11 53 43 AM

This code builds but not sure what the correct context is for best usage. You could take the [UInt8] output from combine([secp256k1.Signing.PublicKey]) and get a hex string using String(bytes:) or just data with Data([UInt8]).

POLAX7 commented 1 year ago

@csjones Yes, it's for multisig. And the reason I got error is because I use the folk of your previous version. Thank you and your replying again.

zeugmaster commented 1 year ago

@csjones

I am also interested in using secp256k1_ec_pubkey_combine to mimic the behaviour of a certain implementation of Chaumian eCash. It uses the combine operation, rather than tweak_add, I presume because it makes more sense in reverse (unblinding a message) and generally fits the implementation better. combine simply adds up the PublicKeys, while add_tweak adds the product of a PublicKey and the Generator Point. I am looking forward to trying the code snippet you provided above. Thanks a lot for all the work you put into this super useful package!

csjones commented 1 year ago

Hey @dariolass 👋

Thank you for the kind words! ☺️ Chaumian eCash support makes a lot of sense and I think would fit nicely into this package's capabilities. Would you share the implementation you're looking to mimic? Ideally, if there is a test case available, we can get an API created for secp256k1_ec_pubkey_combine relatively quickly based on the previous snippet.

zeugmaster commented 1 year ago

Awesome! The project I am trying to partly recreate is cashu. First step of the blinded DHKE involves the addition, which, as an extension of the PublicKey class, uses combine:

# taken from cashu/core/crypto/b_dhke.py
def step1_alice(
    secret_msg: str, blinding_factor: Optional[PrivateKey] = None
) -> tuple[PublicKey, PrivateKey]:
    Y: PublicKey = hash_to_curve(secret_msg.encode("utf-8"))
    r = blinding_factor or PrivateKey()
    B_: PublicKey = Y + r.pubkey  # type: ignore 
    return B_, r

# taken from cashu/core/crypto/secp.py
class PublicKeyExt(PublicKey):
    def __add__(self, pubkey2):
        if isinstance(pubkey2, PublicKey):
            new_pub = PublicKey()
            new_pub.combine([self.public_key, pubkey2.public_key])
            return new_pub
        else:
            raise TypeError("Cant add pubkey and %s" % pubkey2.__class__)

For now I can use tweak_add with a private key because it yields the same result as combine with that private key's .pubkey. I'm just not sure wether the private key can always be accessed at that point (the project uses deterministic key derivation for some things and I honestly don't completely grok all of it yet).

Hope this makes sense and thanks again for helping a newbie!

csjones commented 1 year ago

@zeugmaster I opened up a draft pull request for the combine API here: https://github.com/GigaBitcoin/secp256k1.swift/pull/439

It would be valuable to try the draft API out and provide any feedback you may have. Additionally, starring this repo helps a lot too! 🙂