Post
Topic
Board Development & Technical Discussion
Re: Sipa's secp256k1 for .NET!
by
riplin
on 28/08/2013, 02:49:30 UTC
Should anyone care, I use the following. Saves you from needing a managed C++ project:

Code:

public static class ECDSA
{

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_start", CallingConvention = CallingConvention.Cdecl)]
        private static extern void StartCrypto();

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_stop", CallingConvention = CallingConvention.Cdecl)]
        private static extern void StopCrypto();

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_verify", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VerifySignature(byte[] msg, int msglen, byte[] sig, int siglen, byte[] pubkey, int pubkeylen);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_sign", CallingConvention = CallingConvention.Cdecl)]
        public static extern int SignMessage(byte[] msg, int msglen, byte[] sig, ref int siglen, byte[] seckey, ref int nonce);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_sign_compact", CallingConvention = CallingConvention.Cdecl)]
        public static extern int SignCompact(byte[] msg, int msglen, byte[] sig64, byte[] seckey, ref int nonce, ref int recid);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_recover_compact", CallingConvention = CallingConvention.Cdecl)]
        public static extern int RecoverCompact(byte[] msg, int msglen, byte[] sig64, byte[] pubkey, ref int pubkeylen, int compressed, int recid);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_seckey_verify", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VerifySecretKey(byte[] seckey);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_verify", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VerifyPublicKey(byte[] pubkey, int pubkeylen);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_create", CallingConvention = CallingConvention.Cdecl)]
        public static extern int PublicKeyFromSecretKey(byte[] pubkey, ref int pubkeylen, byte[] seckey, int compressed);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_decompress", CallingConvention = CallingConvention.Cdecl)]
        public static extern int DecompressPublicKey(byte[] pubkey, ref int pubkeylen);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_compress", CallingConvention = CallingConvention.Cdecl)]
        public static extern int CompressPublicKey(byte[] pubkey, ref int pubkeylen);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_privkey_export", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ExportPrivateKey(byte[] seckey, byte[] privkey, ref int privkeylen, int compressed);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_privkey_import", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImportPrivateKey(byte[] seckey, byte[] privkey, int privkeylen);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_privkey_tweak_add", CallingConvention = CallingConvention.Cdecl)]
        public static extern int PrivateKeyTweakAdd(byte[] seckey, byte[] tweak);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_tweak_add", CallingConvention = CallingConvention.Cdecl)]
        public static extern int PublicKeyTweakAdd(byte[] pubkey, int pubkeylen, byte[] tweak);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_privkey_tweak_mul", CallingConvention = CallingConvention.Cdecl)]
        public static extern int PrivateKeyTweakMul(byte[] seckey, byte[] tweak);

        [DllImport("secp256k1.dll", EntryPoint = "secp256k1_ecdsa_pubkey_tweak_mul", CallingConvention = CallingConvention.Cdecl)]
        public static extern int PublicKeyTweakMul(byte[] pubkey, int pubkeylen, byte[] tweak);

}


It's probably a little bit slower when signing a transaction because of the pinvokes when looping to find a correct nonce, but other than that, it's pure C# instead of managed C++.


Edit: actually, now that I looked at the code a bit closer, this is just as fast, if not faster than the managed C++ version, since it's calling managed and unmanaged code in the loop, so it needs to do a pinvoke in the loop too.

Managed C++ is a fickle beast, you never know where it goes managed or native (those transitions are murder). At least with the code above, you know for certain when it happens.