DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 11, 2014, 03:51:54 PM Last edit: April 14, 2014, 03:08:53 AM by DeathAndTaxes |
|
I am looking for a lightweight implementation of basic ECDSA operations, preferably in C#. If not C# then second choice would be Java (as it can be rather easily be translated to c#) but any language is better than nothing.
I am aware that there is bouncy castle however that is a very heavy interconnected library with lots of complex inheritance which makes parsing out the "necessary bits" probably more of a pain. I would prefer a simple flat set of minimal classes but even parsing from a lighter library would be a better option. Yes in general I subscribe to the "never roll your own" theory of development but this is a special case. A vendor sent me a programmable smartcard development kit for evaluation and it has pretty impressive specs. Still it is a smartcard so we are talking tens of KB of memory (combined storage and operating memory) so any code is going to need to be scaled down. SHA-256 (and AES if I wanted to incorporate that for delayed tx signing have hardware support so that is a non-issue. Rolling an implementation of RIPEMD-160 (thanks mono source code) was rather trivial but ECDSA is a whole different beast.
Bitcoin uses a single static curve (secp256k1) so there is no need for library support for named curves or custom curve params, the secp256k1 parameters coded as constants will work just fine.
|
|
|
|
ning
|
|
April 11, 2014, 04:32:44 PM |
|
I have a homemade Erlang implementation for key generation, signing, and verifying. It's basically a set of functions without any inheritance. The thing is, for your case, it's written in Erlang.
|
|
|
|
schalk
Newbie
Offline
Activity: 36
Merit: 0
|
|
April 11, 2014, 08:13:46 PM |
|
I have been in the process of implementing ECDSA using Secp256k1 in C# the last few days. I haven't done much testing yet (still need to write some automated tests!), nor have I had the code reviewed by anyone, so I would strongly advice against using this in production code. Once I have refactored and tidied up a lot of my code, I plan on creating a github repository for it. I would also still like to make this code more separated with different layers of abstraction to allow for better code testability. PerformanceI haven't done much testing in the way of performance, but I have measured it to be about twice the speed of BouncyCastle.NET on a single thread for EC Multiplication and ECDSA Signing/Verifing. When using multithreading it was an even more significant performance increase in comparison to BouncyCastle.NET (I haven't the figures on me sorry). A lot of the performance is based on how fast the BigInteger class is. I have been using System.Numerics.BigInteger which is a lot slower than the likes of gmp. One thing to also keep in mind is that unlike BouncyCastle.NET's BigInteger, System.Numerics.BigInteger is Little Endian. IncludesECdsaSigner (signing/verification/recovery) ECELGamal (public/private key encryption - well key generation) ECEncryption (this is my non standard implementation of encryption with a public key, decryption with a private key. Using AES as the asymmetric cipher and ElGamal as the key generation) ECPoint (does all your ECPoint math) Downloadhttps://mega.co.nz/#!Ao1H1IYJ!JgCnLuWhMy0MYrldjV5A4H7pg9seICnJZYIj30Y-eXM I have also implemented BIP32 (Hierarchical Deterministic Wallets) in a separate project (this uses BouncyCastle), so let me know if you are also in need of that. If you're feeling a bit generous: 15Xi4QCp9wwbXhCniDB2DkgzLjSw49g619
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 11, 2014, 09:32:21 PM |
|
I have a homemade Erlang implementation for key generation, signing, and verifying. It's basically a set of functions without any inheritance. The thing is, for your case, it's written in Erlang.
I would still like to take a look at it if you have the source code available online.
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 11, 2014, 09:34:00 PM |
|
I have been in the process of implementing ECDSA using Secp256k1 in C# the last few days. I haven't done much testing yet (still need to write some automated tests!), nor have I had the code reviewed by anyone, so I would strongly advice against using this in production code. Once I have refactored and tidied up a lot of my code, I plan on creating a github repository for it. I would also still like to make this code more separated with different layers of abstraction to allow for better code testability. PerformanceI haven't done much testing in the way of performance, but I have measured it to be about twice the speed of BouncyCastle.NET on a single thread for EC Multiplication and ECDSA Signing/Verifing. When using multithreading it was an even more significant performance increase in comparison to BouncyCastle.NET (I haven't the figures on me sorry). A lot of the performance is based on how fast the BigInteger class is. I have been using System.Numerics.BigInteger which is a lot slower than the likes of gmp. One thing to also keep in mind is that unlike BouncyCastle.NET's BigInteger, System.Numerics.BigInteger is Little Endian. IncludesECdsaSigner (signing/verification/recovery) ECELGamal (public/private key encryption - well key generation) ECEncryption (this is my non standard implementation of encryption with a public key, decryption with a private key. Using AES as the asymmetric cipher and ElGamal as the key generation) ECPoint (does all your ECPoint math) Downloadhttps://mega.co.nz/#!Ao1H1IYJ!JgCnLuWhMy0MYrldjV5A4H7pg9seICnJZYIj30Y-eXM I have also implemented BIP32 (Hierarchical Deterministic Wallets) in a separate project (this uses BouncyCastle), so let me know if you are also in need of that. If you're feeling a bit generous: 15Xi4QCp9wwbXhCniDB2DkgzLjSw49g619 That is great. Will take a look at it over the weekend. If you host it on github I could help out in getting it production ready.
|
|
|
|
schalk
Newbie
Offline
Activity: 36
Merit: 0
|
|
April 12, 2014, 12:58:35 AM |
|
Cool, let me know if you have questions.
That would be a great help, it can be quite hard squeezing in time to work on projects like these! I'll flick you a pm once it's on github.
|
|
|
|
ning
|
|
April 12, 2014, 01:32:21 AM |
|
I have a homemade Erlang implementation for key generation, signing, and verifying. It's basically a set of functions without any inheritance. The thing is, for your case, it's written in Erlang.
I would still like to take a look at it if you have the source code available online. The verifier is in the public domain ( https://github.com/ningzhang/bitcoin-message-verifier). I haven't put up the source code for signing and key generation online, but I can send you a copy later today. Please PM me your email address if you want to take a look at it.
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 12, 2014, 02:07:41 PM |
|
Cool, let me know if you have questions.
That would be a great help, it can be quite hard squeezing in time to work on projects like these! I'll flick you a pm once it's on github.
I might have jumped the gun but I got the urge to do some "fun" (non-employment) coding this morning. To avoid you duplicating a lot of routine housework I threw it up on a quick repo. https://github.com/TangibleCryptography/Secp256k1I did some very basic refactoring (breaking solution into a class library, demo, and testing projections). Started building out some of the more basic unit tests (hashing & base58 encoding). I already noticed some issues with signatures. The signmessage function is returning the compressed key but the signature is based on the uncompressed key. Most likely we are going to want a keypair class which encapsulates the full bitcoin key "logic" (private key, public key, pubkeyhash, address, etc), that will make it easier to perform signature operations without needing to explicitly ensure compressed vs uncompressed is set properly. Before I tackle that I will be doing some more basic refactoring to use some c# language features like extension methods. I used Nunit for testing module and it should pull it directly from Nuget if needed. I have no problem with Visual Studio internal testing framework (or even Resharper's test framework) but I can't remember which versions of VS don't have testing support. I figured Nunit might be more open to users of even express version of VS. Since this is started from your code, if you wish to clone this to your github repo go ahead. I have no problem taking this down once you have a public copy up. If you want you can give me commit access or if not I can do pull requests from your repo, all depends on how hands on you want to be. I would recommend adding a license (COPYING) to the root of the repo. Not sure if you have any preference, if not I am included to use modified BSD ( ). Lastly the solution is more a lightweight bitcoin crypto library in C#, not just Secp256K1 library, so my boilerplate /Secp256k1 doesn't really describe the scope accurately so it might make sense to change that name of the solution and repo to something more fighting (and less verbose than "lightweight crypto library from bitcoin in C#").
|
|
|
|
schalk
Newbie
Offline
Activity: 36
Merit: 0
|
|
April 13, 2014, 11:04:08 PM |
|
Sorry, was just out for the weekend. I was actually at Kim Dotcom's mansion for the Internet Party picnic, it was an amazing weekend. Interestingly the first person I spoke to at the event use to be a developer at MtGox. Thanks for that, but I will probably put up a repository later this week and I will give you commit access. just thought it would look good to have something like this on my CV. Awesome - cheers for that. I have already noted down the issue with returning a compressed key everytime, it's on my mental todo list. Nunit is awesome, my personal preference of a testing framework, what mocking framework do you usually use? I'm quite a fan of Telerik's JustMock. Yeah, my extensions class is a complete mess at the moment. What's your opinion on extension for strings like HexToBigInteger, HexToBytes and for byte[] ToBigIntegerUnsigned etc? I wasn't sure if those are better kept as static methods or extension methods. Also, your point about adding in a keypair class. I wasn't too sure about this, I know that the likes of Bitcoinj use this approach. But I was considering maybe separating things out a bit more, having classes like: PrivateKey - then PrivateKey would have a property called PublicKey PublicKey - then PublicKey will have a property called PubKeyHash PubKeyHash - which is essentially the bitcoin address which can be representing with different encoding methods. I haven't put much thought into the Address class. But I was thinking about maybe making the Address class abstract and having classes like PubKeyHashAddress and ScriptHashAddress inheriting from Address. What are your thoughts?
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 14, 2014, 03:38:53 AM Last edit: April 14, 2014, 09:38:01 PM by DeathAndTaxes |
|
Awesome - cheers for that. I have already noted down the issue with returning a compressed key everytime, it's on my mental todo list. Nunit is awesome, my personal preference of a testing framework, what mocking framework do you usually use? I'm quite a fan of Telerik's JustMock. Moq is really the only framework I have used although they are similar enough I don't see that being much of an issue. Yeah, my extensions class is a complete mess at the moment. What's your opinion on extension for strings like HexToBigInteger, HexToBytes and for byte[] ToBigIntegerUnsigned etc? I wasn't sure if those are better kept as static methods or extension methods. The extensions from "true" types/classes is straightforward. byte[] -> BigInteger, ulong ->VarInt, etc. The extensions from "psuedo classes" gets a little messier. Right now "hex" is just a string so having extension methods off of the string class which aren't applicable for non hex strings starts to feel a little kludgy. On the other hand I am not a fan of the static class with utility methods unless there is no other choice. I am wondering if a lightweight class for HexString would be a better design choice. Maybe something like this? HexString privHex = new HexString("E9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262");
var aBigInt = privHex.ToBigInteger(); ... Console.WriteLine("Private Key (hex) {0}", privHex.ToString()); Not 100% sure still going back and forth on that one. Also, your point about adding in a keypair class. I wasn't too sure about this, I know that the likes of Bitcoinj use this approach. But I was considering maybe separating things out a bit more, having classes like: PrivateKey - then PrivateKey would have a property called PublicKey PublicKey - then PublicKey will have a property called PubKeyHash PubKeyHash - which is essentially the bitcoin address which can be representing with different encoding methods. Well Address is the versioned and checksummed PubKeyHash. Still that may work. if a KeyPair class was used I do think it should be lightweight mainly facilitating conversion between the related objects. I don't like bitcoinj approach on this as it makes the KeyPair (ECKey I believe) class very heavy and there isn't a clear separation of the objects. I haven't put much thought into the Address class. But I was thinking about maybe making the Address class abstract and having classes like PubKeyHashAddress and ScriptHashAddress inheriting from Address. That may work. The relationships between Bitcoin objects is complex and it makes having clear inheritance "interesting". To throw a monkey wrench into your structure above keep in mind that WIFPrivateKey, and Addressees are both implementations of the Base58Check structure (version +checksum added to a payload encoded in base58).
|
|
|
|
doof
|
|
April 14, 2014, 11:01:27 AM |
|
Let me know how you get on. Been doing a lot of c# bitcoin dev. I'm using bouncy but might be doing a similar thing to you soon.
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 14, 2014, 03:38:59 PM |
|
Let me know how you get on. Not sure what you are asking here.
|
|
|
|
DeathAndTaxes (OP)
Donator
Legendary
Offline
Activity: 1218
Merit: 1079
Gerald Davis
|
|
April 14, 2014, 09:38:37 PM |
|
Synced a few commits. Some basic housekeeping stuff as well as improving VarInt and VarString support.
|
|
|
|
deepceleron
Legendary
Offline
Activity: 1512
Merit: 1036
|
|
April 16, 2014, 10:34:46 AM |
|
Let me know how you get on. Not sure what you are asking here. Interpretation: "please keep me updated with the progress you are making"
|
|
|
|
Nicolas Dorier
|
|
April 20, 2014, 12:52:28 AM |
|
I don't know if it can help you, but I took the last two week too code a bitcoin port. You want to sign data ? var key = new Key(); var sig = key.Sign(data) you want to verify data ? key.PubKey.Verify(data,sig) If you can get ride of BouncyCaslte, please, let me know. (I'm not using tons of stuff of their library, so I guess you can get their source code, recompile the only strict minimum for ECDSA, link NBitcoin to it, and you are good to go) I coded tons of unit test so you can see if you broke something by doing that. Github : https://github.com/NicolasDorier/NBitcoin/blob/master/NBitcoin
|
Bitcoin address 15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe
|
|
|
|