Pages:
Author

Topic: Is a "safely compliant" (semi-)centralized CoinJoin service possible? - page 2. (Read 459 times)

member
Activity: 378
Merit: 93
Enable v2transport=1 and mempoolfullrbf=1
I don't know how many of those technologies you mentioned (DHT, gossip, homomorphic encryption/multiparty computation) are already implemented in JoinMarket and Joinstr. Specificly homomorphic encryption and multiparty computation could be a game-changer if that part is still lacking, because they would allow a similar level of privacy than a trusted centralized service.

While Bitcoin's pseudonymous nature offers a level of privacy, all transactions are public on the blockchain, allowing for potential analysis that could link identities to transactions. To enhance privacy and security, advanced cryptographic techniques such as homomorphic encryption can be applied. using Microsoft SEAL, a C++ library for homomorphic encryption, to demonstrate how privacy could be further protected in Bitcoin transactions, particularly in privacy-focused protocols like CoinJoin.

Homomorphic encryption allows computations on encrypted data without needing to decrypt it first. This property can be particularly useful in Bitcoin transactions for various reasons...  Users can participate in transactions without revealing their transaction amounts or other sensitive data to other parties or the public blockchain.

...

While it's not 100% solid idea yet could be worth exploring further.

The WabiSabi coinjoin protocol deployed in Wasabi Wallet and BTCPay Server uses homomorphic value commitments  Grin

Check out the WabiSabi research paper: https://eprint.iacr.org/2021/206.pdf

The problem (and feature) of JoinMarket lies in takers covering the costs of inputs and outputs for their makers.  When selecting an entity to mix coins with, I'm essentially covering the expenses for their inputs and outputs.  This quickly renders it unappealing in the present context, where we pay more than 15 sat/vB.  

What's required is a network with no distinctions between makers and takers, that consists solely of users leveraging the network to create a shared space, because the main problem with coinjoins is being online at the same time with the other joiners.  Once a collective of participants is created, they could merge their inputs, generate blinded outputs, and cover only their respective portions of the costs.  I believe this network is feasible to create.

This network has already been created, the coinjoin protocol you are referring to is called "WabiSabi":

- Users directly cover their own block space costs
- No distinction between makers and takers
- Timeout based rounds for liquidity
sr. member
Activity: 364
Merit: 300
Such a service would be able to charge a (low) fee, for example for a kind of API subscription, but would not be a money transmitter in any way as it's not at all involved in the creation of transactions.

This doesn't resolve the issue.  You're still required to place trust in the service to provide you with accurate information.  There are still security concerns, just like previously. 

This would make a JoinMarket-style CoinJoin network possible where users could participate with their SPV wallets (Electrum, Sparrow et al.).

The problem (and feature) of JoinMarket lies in takers covering the costs of inputs and outputs for their makers.  When selecting an entity to mix coins with, I'm essentially covering the expenses for their inputs and outputs.  This quickly renders it unappealing in the present context, where we pay more than 15 sat/vB. 

What's required is a network with no distinctions between makers and takers, that consists solely of users leveraging the network to create a shared space, because the main problem with coinjoins is being online at the same time with the other joiners.  Once a collective of participants is created, they could merge their inputs, generate blinded outputs, and cover only their respective portions of the costs.  I believe this network is feasible to create.  Fidelity bonds could still serve to discourage sybil attackers. 

Instead of a central server holding this info (which could draw legal and security concerns)why not let the users themselves manage their UTXOs in a peer-to-peer manner?

Sybil attacks.  By selecting random users, you're essentially relying on the assumption that an attacker doesn't control all of them and inject their inputs.  While you might think your coins have been successfully mixed, the attacker would still be aware of your outputs. 
hero member
Activity: 1241
Merit: 623
OGRaccoon
While Bitcoin's pseudonymous nature offers a level of privacy, all transactions are public on the blockchain, allowing for potential analysis that could link identities to transactions. To enhance privacy and security, advanced cryptographic techniques such as homomorphic encryption can be applied. using Microsoft SEAL, a C++ library for homomorphic encryption, to demonstrate how privacy could be further protected in Bitcoin transactions, particularly in privacy-focused protocols like CoinJoin.

Homomorphic encryption allows computations on encrypted data without needing to decrypt it first. This property can be particularly useful in Bitcoin transactions for various reasons...  Users can participate in transactions without revealing their transaction amounts or other sensitive data to other parties or the public blockchain.

Secure Multi-party Computations, enables the creation of complex multi-party protocols where inputs are kept private.

Setting up Encryption Each participant uses a common encryption scheme set up using Microsoft SEAL. This ensures all parties can operate on the data homomorphically. users encrypt their UTXO values. This encryption does not reveal the amount of bitcoins each user intends to mix, but allows operations to be performed on the encrypted values.

Code:
Ciphertext encrypted_utxo = encrypt_utxo_amount(context, utxo_amount, public_key, encryptor);
Serialize and Share Encrypted UTXOs, Once encrypted, UTXO data can be serialized and securely shared with other participants or a coordinating server without revealing the actual values.

Code:
string serialized_utxo = serialize_encrypted_utxo(encrypted_utxo);
Aggregate Encrypted UTXOs, A trusted coordinator or the participants themselves can aggregate the encrypted UTXOs. This aggregation is performed homomorphically, ensuring that no individual inputs are exposed.

Code:
Ciphertext aggregated_utxos = aggregate_utxos({encrypted_utxo1, encrypted_utxo2}, evaluator);
Check Aggregated UTXOs Against Threshold: To ensure the transaction meets certain criteria (e.g., minimum input threshold for a CoinJoin), a homomorphic operation checks if the aggregated encrypted value meets the required threshold.

Code:
bool meets_threshold = check_threshold(context, aggregated_utxos, threshold, decryptor, encoder);
Finalize Transaction: If the check passes, the transaction can proceed. This step would typically require converting the homomorphically encrypted data into a format suitable for a Bitcoin transaction, which may involve securely decrypting the data under strict protocols or through a zero-knowledge proof mechanism to maintain confidentiality.


Code:
#include
#include "seal/seal.h"

using namespace std;
using namespace seal;

// setup the encryption context
shared_ptr setup_context() {
    EncryptionParameters parms(scheme_type::ckks);
    size_t poly_modulus_degree = 8192;
    parms.set_poly_modulus_degree(poly_modulus_degree);
    parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, { 60, 40, 40, 60 }));

    auto context = SEALContext::Create(parms);
    return context;
}

// encrypt a UTXO amount
Ciphertext encrypt_utxo_amount(shared_ptr context, double amount, PublicKey public_key, Encryptor& encryptor) {
    CKKSEncoder encoder(context);
    Plaintext plain;
    double scale = pow(2.0, 40);
    vector input{ amount };
    encoder.encode(input, scale, plain);

    Ciphertext encrypted;
    encryptor.encrypt(plain, encrypted);
    return encrypted;
}

// serialize a ciphertext (for sharing or storage)
string serialize_encrypted_utxo(const Ciphertext& encrypted) {
    stringstream ss;
    encrypted.save(ss);
    return ss.str();
}

// deserialize a ciphertext
Ciphertext deserialize_encrypted_utxo(shared_ptr context, const string& data) {
    stringstream ss(data);
    Ciphertext encrypted(context);
    encrypted.load(context, ss);
    return encrypted;
}

// aggregate encrypted UTXOs
Ciphertext aggregate_utxos(const vector& utxos, Evaluator& evaluator) {
    Ciphertext aggregated = utxos[0];
    for (size_t i = 1; i < utxos.size(); ++i) {
        evaluator.add_inplace(aggregated, utxos[i]);
    }
    return aggregated;
}

// check if aggregated UTXOs meet the threshold
bool check_threshold(shared_ptr context, const Ciphertext& aggregated, double threshold, Decryptor& decryptor, CKKSEncoder& encoder) {
    // Subtract the threshold homomorphically
    Plaintext plain_threshold;
    encoder.encode(vector{threshold}, aggregated.scale(), plain_threshold);
    Ciphertext encrypted_threshold;
    Encryptor encryptor(context, decryptor.public_key());
    encryptor.encrypt(plain_threshold, encrypted_threshold);

    Ciphertext result;
    Evaluator evaluator(context);
    evaluator.sub(aggregated, encrypted_threshold, result);

    // Decrypt
    Plaintext result_plain;
    decryptor.decrypt(result, result_plain);
    vector result_vector;
    encoder.decode(result_plain, result_vector);

    return result_vector[0] >= 0;
}

int main() {
    auto context = setup_context();
    KeyGenerator keygen(context);
    PublicKey public_key = keygen.public_key();
    SecretKey secret_key = keygen.secret_key();
    Encryptor encryptor(context, public_key);
    Decryptor decryptor(context, secret_key);
    CKKSEncoder encoder(context);

    Ciphertext encrypted_utxo1 = encrypt_utxo_amount(context, 2.5, public_key, encryptor);
    Ciphertext encrypted_utxo2 = encrypt_utxo_amount(context, 1.7, public_key, encryptor);

    vector utxos{ encrypted_utxo1, encrypted_utxo2 };
    Ciphertext aggregated = aggregate_utxos(utxos, Evaluator(context));

    bool meets_threshold = check_threshold(context, aggregated, 4.0, decryptor, encoder);
    cout << "Aggregated UTXOs meet threshold: " << (meets_threshold ? "true" : "false") << endl;

    return 0;
}

While it's not 100% solid idea yet could be worth exploring further.
legendary
Activity: 3906
Merit: 6249
Decentralization Maximalist
https://joinstr.xyz somewhat match idea you described.
Looks really interesting, thank you! It seems however still not be ready for mainnet, but definitely a solution which is worthy to observe.

snip
Some good ideas here, thanks! Yes, what I had thought about was that users manage the UTXOs in a P2P manner. But my question was in reality if you could build a compliant business model with such an idea.

I don't know how many of those technologies you mentioned (DHT, gossip, homomorphic encryption/multiparty computation) are already implemented in JoinMarket and Joinstr. Specificly homomorphic encryption and multiparty computation could be a game-changer if that part is still lacking, because they would allow a similar level of privacy than a trusted centralized service.

My main doubt was about the need of a full node. JoinMarket requires it, Joinstr seems not, so it may already fit the idea of the service I had in mind. Possible business model could include to act as a market maker or even as a specialized Nostr relay maybe.
legendary
Activity: 2870
Merit: 7490
Crypto Swap Exchange
This would make a JoinMarket-style CoinJoin network possible where users could participate with their SPV wallets (Electrum, Sparrow et al.).

Am I missing something? Does such a service perhaps already exist?

https://joinstr.xyz somewhat match idea you described.
hero member
Activity: 1241
Merit: 623
OGRaccoon
I think something like a decentralized network where users could engage in privacy-enhancing transactions without the risk of running afoul of regulatory bodies is needed.  Given the situations with Samourai and Whirlpool and the scrutiny it faced it's crucial to brainstorm a structure that avoids being labeled as a money transmitter

The first challenge is managing the pool of UTXOs that users wish to mix.

Instead of a central server holding this info (which could draw legal and security concerns)why not let the users themselves manage their UTXOs in a peer-to-peer manner?

Distributed Hash Table? Utilize a DHT to store and retrieve UTXO information, each UTXO can be indexed by a hash derived from its attributeswhich could include the transaction ID and output index, masked with a privacy-preserving algorithm to prevent tracking

Adding a gossip protocol to propagate UTXO information across the network.  This ensures redundancy and availability of UTXO data without relying on a central server.  It would also be possible to use cryptographic commitment schemes to ensure that UTXO data remains confidential until participants are ready to reveal them. This can prevent premature exposure of UTXO details.

Apply homomorphic encryption to allow certain computations to be carried out on UTXOs, such as verification of amounts and eligibility, without revealing the underlying values.

Multi-Party Computation could be used for constructing the transaction where each participant computes a part of the transaction without revealing their inputs to others.  This can be crucial for maintaining the confidentiality of which inputs and outputs belong to whom.

Just some ideas  Smiley
legendary
Activity: 3906
Merit: 6249
Decentralization Maximalist
I think everybody and their grandma has now already heard of the Samourai case.

I was thinking about if a service which could make CoinJoins easier would be possible in a totally compliant way, without any danger of it to be considered a "money transmitter" by any authority. (I still think the American authorities are wrong with Whirlpool being a "money transmitter", but I haven't seen the code, so I can't be sure.)

First, what do we need to build a CoinJoin facilitating service? First, some kind of storage for a pool of UTXOs which are available for CoinJoins. I guess Whirlpool did this in a centralized way on its server. But in theory this could be done by the users themselves: from the moment on they offer their own UTXO, they can get informations about other UTXOs which are available. (This is actually how JoinMarket seems to work afaik. But Joinmarket is not what I'm asking for - I'm thinking about a model to create a centralized service which could offer a fee but would be easier to use than JoinMarket.)

So the UTXOs would circulate in a P2P network completely independent from the centralized server.*

Second part would be the entity "building" the CoinJoin transactions. This could also happen in the P2P network. So basically, once an user sees enough UTXOs to form a CoinJoin, he uses let's say 5 or 10 UTXOs from this decentralized pool and builds his transaction, signs it and broadcasts it inside the P2P network, so all peers which have contributed UTXOs can sign it.

What can the centralized server do to make CoinJoins easy? As far as I have understood JoinMarket, you need a full node to participate there because otherwise there are security concerns, and thus it's limited to a relatively small and wealthy Bitcoin user group.

So the centralized server thus could simply offer you this service: a trusted Bitcoin Core node you can connect to and you can query as if it was your own Bitcoin Core node. So every user can always be sure that the UTXOs he uses for his CoinJoin transaction are really there.

Such a service would be able to charge a (low) fee, for example for a kind of API subscription, but would not be a money transmitter in any way as it's not at all involved in the creation of transactions.

This would make a JoinMarket-style CoinJoin network possible where users could participate with their SPV wallets (Electrum, Sparrow et al.).

Am I missing something? Does such a service perhaps already exist?



*Yes, chain analysis companies could of course use this P2P network too, but this would happen to all CoinJoin models.
Pages:
Jump to: