<p>Starting off from a sha256 hash of a threshold pubkey, how can I generate a valid secp256k1 public key?</p>
<p>The challenge is that the 32 bytes of the hash does not always fall within secp256k1 range, so I suspect I'd need some additional elliptic curve operation on the hash to bring it get to a byte string I can use to generate a valid pubkey.</p>
<p>So far I've tried taking a modulus of the hash against constant secp256k1 curve order. Didn't work, probably because I don't fully understand the elliptic curve math necessary here...</p>
<pre><code>/// Rust 
/// 
/// Converts a federation id to a public key to which we don't know the
/// private key
///
/// That is ok because we only use it for adding a route
/// hint to LN invoices that tells fedimint clients that the invoice can
/// only be paid internally. Since no LN node with that pb key can exist
/// other LN senders will know that they cannot pay the invoice.
pub fn to_fake_ln_pub_key(seed: threshold_crypto::PublicKey) -&gt; anyhow::Result&lt;secp256k1::PublicKey&gt; {
    let mut bytes = [0u8; 33];
    bytes[0] = 0x02;

    let modulus = BigUint::from_bytes_be(
        &amp;&lt;Sha256 as bitcoin_hashes::Hash&gt;::hash(&amp;seed).into_inner(),
    ) % BigUint::from_bytes_be(&amp;secp256k1::constants::CURVE_ORDER);

    bytes[1..].copy_from_slice(&amp;modulus.to_bytes_be());

    Ok(secp256k1::PublicKey::from_slice(&amp;bytes)?)
}
</code></pre>
<p><strong>Motivation and Context:</strong></p>
<p>The pubkey I'm looking to generate in this way will be used as a source node id marker in a valid invoice that is only payable between clients within a Fedimint federation. In this scenario, the threshold pubkey we use as 'seed data' is actually the federation ID.</p>
<p>One client within a federation would generate a lightning invoice, adding a route hint with source node id set to this pubkey we are looking to generate.</p>
<p>Another client within the federation looking to pay this invoice should be able to generate a matching pubkey marker from federation id threshold pubkey, and match it against the marker.</p>
<p>With this marker, they can do a transaction between themselves within the federation without ever going over the lightning network.</p>
<p><strong>Ref:</strong></p>
<ul>
<li><a href="https://github.com/fedimint/fedimint/pull/2640" rel="nofollow noreferrer">https://github.com/fedimint/fedimint/pull/2640</a></li>
<li><a href="https://github.com/fedimint/fedimint/issues/2618" rel="nofollow noreferrer">https://github.com/fedimint/fedimint/issues/2618</a></li>
</ul>

CC BY-SA 4.0
2023-06-16T12:16:16.623Z
What properties does this public key need? Is it ok if *nobody* knows the corresponding private key? If not, who should be able to derive it?
Pieter Wuille
CC BY-SA 4.0
2023-06-17T13:12:19.450Z
I believe we only need the public key to be valid. We conventionally pick an even parity when creating the public key.
Nobody needs to know the corresponding private key and while anyone with sufficient information should be able to derive it, we (or they) should never use this key to sign anywhere
okjodom
CC BY-SA 4.0
2023-06-17T13:48:16.003Z
There exist various schemes for "hashing to the curve", with various properties, but among others, guarantee that nobody can compute the corresponding private key. They're nontrivial to implement, though. Alternatively, you can just use "Hash(data) * G" which allows anyone with access to the data to get the private key. Lastly, "Hash(data) * G + H" (with H a second generator) works too, has similar properties to hash-to-curve, and a lot easier to implement, but slower.
Pieter Wuille
CC BY-SA 4.0
2023-06-18T01:11:16.860Z
Preferred and implemented "Hash(data) * G" scheme. We can later iterate our scenario to a scheme where nobody can compute the private key. Thanks
okjodom
<cryptography><invoices>
Derive Secp256k1 curve public key starting off from known 32 bytes string
okjodom
# Derive Secp256k1 curve public key starting off from known 32 bytes string

(Asked by: username_0 on 2023-06-15)

Starting off from a sha256 hash of a threshold pubkey, how can I generate a valid secp256k1 public key?

The challenge is that the 32 bytes of the hash does not always fall within secp256k1 range, so I suspect I'd need some additional elliptic curve operation on the hash to bring it get to a byte string I can use to generate a valid pubkey.

So far I've tried taking a modulus of the hash against constant secp256k1 curve order. Didn't work, probably because I don't fully understand the elliptic curve math necessary here...

```
/// Rust 
/// 
/// Converts a federation id to a public key to which we don't know the
/// private key
///
/// That is ok because we only use it for adding a route
/// hint to LN invoices that tells fedimint clients that the invoice can
/// only be paid internally. Since no LN node with that pb key can exist
/// other LN senders will know that they cannot pay the invoice.
pub fn to_fake_ln_pub_key(seed: threshold_crypto::PublicKey) -> anyhow::Result<secp256k1::PublicKey> {
    let mut bytes = [0u8; 33];
    bytes[0] = 0x02;

    let modulus = BigUint::from_bytes_be(
        &<Sha256 as bitcoin_hashes::Hash>::hash(&seed).into_inner(),
    ) % BigUint::from_bytes_be(&secp256k1::constants::CURVE_ORDER);

    bytes[1..].copy_from_slice(&modulus.to_bytes_be());

    Ok(secp256k1::PublicKey::from_slice(&bytes)?)
}

```

**Motivation and Context:**

The pubkey I'm looking to generate in this way will be used as a source node id marker in a valid invoice that is only payable between clients within a Fedimint federation. In this scenario, the threshold pubkey we use as 'seed data' is actually the federation ID.

One client within a federation would generate a lightning invoice, adding a route hint with source node id set to this pubkey we are looking to generate.

Another client within the federation looking to pay this invoice should be able to generate a matching pubkey marker from federation id threshold pubkey, and match it against the marker.

With this marker, they can do a transaction between themselves within the federation without ever going over the lightning network.

**Ref:**

* <https://github.com/fedimint/fedimint/pull/2640>
* <https://github.com/fedimint/fedimint/issues/2618>

**Tags:** cryptography, invoices

> **Comments:**
> **username_1**: What properties does this public key need? Is it ok if *nobody* knows the corresponding private key? If not, who should be able to derive it?  
> **username_0**: I believe we only need the public key to be valid. We conventionally pick an even parity when creating the public key. Nobody needs to know the corresponding private key and while anyone with sufficient information should be able to derive it, we (or they) should never use this key to sign anywhere  
> **username_1**: There exist various schemes for "hashing to the curve", with various properties, but among others, guarantee that nobody can compute the corresponding private key. They're nontrivial to implement, though. Alternatively, you can just use "Hash(data) * G" which allows anyone with access to the data to get the private key. Lastly, "Hash(data) * G + H" (with H a second generator) works too, has similar properties to hash-to-curve, and a lot easier to implement, but slower.  
> **username_0**: Preferred and implemented "Hash(data) * G" scheme. We can later iterate our scenario to a scheme where nobody can compute the private key. Thanks  

---

## 0 answers

