Open indutny opened 7 years ago
From using this myself, the only issues I've had a lot of back-and-forth on, having to double check code several times: has been around types. To date, I've always found a type error to be the major cause for serious issues, and for that some of the methods acceptance of different types often scare me.
I could use a type enforcing library/transpiler, but the API would still be very liberal.
Personally, I find that the encoding argument for various API functions is too hard to understand.
@indutny I agree, which is why I like how you've done the export functions in bn.js
, toArray
, toBuffer
, toArrayLike
etc. It is more explicit and tested.
I'd say the same for from*
would be ideal.
my main issues is just with the Objects, curves vs keys vs signatures it's not always intuitive to me sometimes what's a method on what vs a parameter, e.g. verify is a method of the curve that takes the key as a param, but sign is a method on the key
I worked the elliptic curve API for libbitcion a few years ago. We had similar API woes, so we decided to break away from the original object-oriented approach and try something more "mathematical". This made the library much easier to work with, and was a great success.
Translating the lessons from libbitcoin into a more Javascript-ish API would produce something like:
exports.secp256k1 = {
Point, // Constructor
Scalar // Constructor
}
exports.ed25519 = {
Point, // Constructor
Scalar // Constructor
}
// Likewise for the other curves...
You might use it like this:
const { secp256k1 } = require('elliptic')
// Scalars are modulo the curve order:
const privateKey = new secp256k1.Scalar('c2e8a67f371340b8a0c982f0854bb699...')
// To go from a scalar to a point, use the Point constructor:
const publicKey = new secp256k1.Point(privateKey)
// Somebody sent us their point, so let's do Diffie-Hellman:
const sharedSecret = privateKey.mul(otherPublicKey)
// Deriving HD addresses for bitcoin? We can add points to scalars:
const step = new secp256k1.Scalar(hmacSha512(bip32.stuff...))
const childPubkey = parentPubKey.add(step)
// We can also add scalars to scalars to get the private keys for those addresses:
const childKey = parentKey.add(step)
Basically, this splits the existing Keypair
type into its two mathematical components. Anybody working with an EC math library should already be familiar with these concepts, so the goal is to create less of a mental burden going between math and code.
A Scalar
type internally keep track of its corresponding point around for performance reasons, but that's an implementation detail. From the outside, the API matches what somebody would expect mathematically.
The Scalar
and Point
classes should be immutable, just like Javascript strings and numbers. Instead of modifying the object in-place, you just return a new object with the requested changes. This makes things a lot easier to reason about, and seems to be catching on in modern Javascript API design.
The Scalar
type might have a makeSignature
method, which accepts a hash to sign. The Point
type would then have a checkSignature
to match. Basically, all the algorithms that elliptic currently splits out, like EDDSA, just become methods on these two classes. It's not clear whether signatures should also have their own data type, or just be returned directly in DER format.
Other methods might include format converters like toDER
and fromDER
and information queries like isEven
and getX
. The methods on the Point
class will generally be a subset of the methods on the Scalar
class, since private keys are more powerful than public keys.
I know this is a big change, but hopefully this seems reasonable.
Hello everyone!
As many of you know already, (some of) the API for this library kind of sucks. While underlying primitives and implementation are quite fast, method names, arguments and the rest is really messed up.
I would like to ask you to help me define the better sets of APIs that we could move to in a next major version. It is fine to bump the version just to get them, and I don't mind support both for some time.
Let's discuss it here, and once the consensus will be reached - implement it!
cc @ryanxcharles @wanderer @alexeykudinkin @calvinmetcalf @fanatid @braydonf and everyone who is interested!