I could not find an implementation of HKDF in Erlang on Hex.pm, so I figured why not make one myself.

There is one on github, but it is

a) as noted, not published on Hex.pm

b) uses the old `crypto`

api (actually so does the `hkdf`` library for Elixir I believe).

I think this is what I am looking for, but not sure what to do once I have the OKM.

Is it possible to use this to create a EC256 public private keypair?

I don’t know much about ECC yet to be quite honest, the best I can probably do is point towards this lovely book on cryptography that might give an answer.

It is certainly possible, though doing so in Erlang/Elixir may not be so easy.

A P-256 private key is essentially a random number d that satisfies 0 < d < n where n is the order of the curve. You can get the order of P256 from `:crypto`

using:

`{{:prime_field, p}, {a, b, s}, g, n, h} = :crypto.ec_curve(:secp256r1)`

Since a random 256-bit number may or may not be within the required range, you’re going to have to either run the KDF multiple times (e.g. with a sequence number as part of the IKM) until you get a value you can use, or use the NIST FIPS-186-4 B.4.1 procedure of producing 64 bits extra for the input and then calculating:

```
d =
input # 40 bytes pseudo random binary
|> :binary.decode_unsigned()
|> rem(:binary.decode_unsigned(n) - 1)
|> Kernel.+(1)
|> :binary.encode_unsigned()
```

You can then wrap this in a `ECPrivateKey`

record:

`{:ECPrivateKey, 1, d, {:namedCurve, : secp256r1}, public_key_goes_here}`

To calculate the public key, however, requires calculation of dG, where G is the base point of the curve. Unfortunately Erlang’s `:crypto`

does not provide a function to multiply points on a curve. The closest thing would be to use `:public_key.compute_key/2`

on d and G, which will give you the x coordinate of the point. You could then calculate the two candidates for y be evaluating the curve equation for x. I guess you could then use trial and error to see which of `{x, y}`

and `{x, p - y}`

is the valid public key for your private key…? Or you’d have to implement point multiplication in Elixir, which is not going to be terribly efficient

Anyway, TL;DR, it is theoretically possible, but you should probably not do it in Erlang/Elixir with custom code (including the code shown above) because implementing crypto from scratch is a very bad idea™ for most of us…

Just for fun, here’s a working module in pure Elixir, which works with HKDF:

```
iex(1)> priv = :hkdf.derive(:sha384, <<"Never gonna give you up">>, 42) |> EC.from_kdf(:secp256r1)
{:ECPrivateKey, 1,
<<152, 241, 110, 3, 198, 241, 200, 2, 25, 201, 250, 119, 187, 21, 134, 203,
162, 76, 191, 189, 65, 114, 109, 178, 62, 15, 94, 78, 182, 234, 125, 166>>,
{:namedCurve, :secp256r1},
<<4, 218, 207, 201, 92, 80, 255, 49, 227, 206, 196, 95, 97, 157, 68, 28, 156,
56, 238, 125, 99, 119, 54, 64, 197, 154, 8, 210, 27, 211, 249, 114, 241, 102,
48, 248, 183, 26, 218, 155, 3, 159, 251, 230, 229, ...>>}
iex(2)> pub = {{:ECPoint, elem(priv, 4)}, elem(priv, 3)}
{{:ECPoint,
<<4, 218, 207, 201, 92, 80, 255, 49, 227, 206, 196, 95, 97, 157, 68, 28, 156,
56, 238, 125, 99, 119, 54, 64, 197, 154, 8, 210, 27, 211, 249, 114, 241,
102, 48, 248, 183, 26, 218, 155, 3, 159, 251, 230, 229, 6, 156, ...>>},
{:namedCurve, :secp256r1}}
iex(3)> :public_key.sign("Hello, world!", :sha256, priv)
<<48, 70, 2, 33, 0, 154, 43, 221, 141, 160, 193, 248, 50, 65, 153, 117, 251, 67,
236, 144, 109, 211, 170, 249, 88, 160, 109, 126, 155, 194, 214, 28, 108, 237,
109, 148, 232, 2, 33, 0, 163, 198, 59, 141, 205, 103, 159, 179, 180, 37, ...>>
iex(4)> :public_key.verify("Hello, world!", :sha256, v(), pub)
true
```

But don’t use it!

I was looking at this post https://blog.lelonek.me/bitcoin-extended-keys-773ab100c59f Section: " Master private key and chain code"

Which suggested it was as simple as the following.

```
<<private_key::binary-32, chain_code::binary-32>> = hashed_seed
{private_key, chain_code}
{public_key, _} = :crypto.generate_key(:ecdh, :secp256k1, private_key)
```

I guess I’m missing some key details

Using `:crypto.generate_key/3`

to derive a public key from a private key would certainly save a lot of work. It seems to work for SECP 256k1, but not 256r1 (NIST P-256). **Edit**: actually, it does work, I’ll update the gist…

Also, it seems to assume the private key value passed in is indeed a valid private key, but a random 32-bit value would have to be clamped to the curve’s order. Failing to do so would result in a significant bias towards lower scalar values, as values larger than the order would effectively wrap around.