1

I am trying to setup an account constraint as such:

#[account(
    init,
    payer = creator,
    space = StateObj::space(),
    seeds = [
        b"some-seed",
        user_partner0.key().as_ref(),
        user_partner1.key().as_ref(),
    ],
    bump,
)]

However, I realized that if you are doing this, you are going to need to know the order in which the seeds were used in order to get the correct address. I don't like this pattern and would prefer to have something like a hash of the two pubkeys and use it as a seed.

Ideally I would have a seeds function which could be called to easily do this:

#[account(
    init,
    payer = creator,
    space = StateObj::space(),
    seeds = [
        b"some-seed",
        StateObj::seeds(b"some-seed", user_partner0.key(), user_partner1.key()),
    ],
    bump,
)]

I was having some trouble with lifetimes as well since I needed to return a &[&[u8]] If someone knows how to handle the lifetime issue and how to hash these two pubkeys, I would be super grateful!

2 Answers 2

2

The seeds are already going to be hashed behind the scenes to generate the PDA, so hashing them in advance won't really buy you anything.

Would sorting the pubkeys first be sufficient for your application?

3
  • hmmm that is an interesting idea... numerically sorting might be a decent way to think about this... I am still interested in how I would hash if i were to do it just for the sake of knowing... but pragmatically speaking this is probably the easiest answer. Commented Jul 20, 2022 at 20:30
  • 1
    like i said, i don't see a point in hashing in this case, it's just going to burn compute budget. if you're just asking about how to hash from a program generically, you can use the helper functions from the hash module of the solana-program crate. they use the sol_sha256 syscall under the hood when called from a program. But that should be a new question!
    – trent.sol
    Commented Jul 20, 2022 at 21:01
  • Good to know. This is probably all the direction I need to explore and play with it. Though logically your solution makes more sense. Commented Jul 20, 2022 at 21:10
4

In order to get a commutative function of the two seed inputs, I would just XOR the keys together.

fn couple(prt1: Pubkey, prt2: Pubkey) -> Pubkey {
  let a1: [u8; 32] = prt1.to_bytes();
  let a2: [u8; 32] = prt2.to_bytes();
  let mut ac: [u8; 32];
  for i in 0..32 {
    ac[i] = a1[i] ^ a2[i];
  }
  return Pubkey::new_from_array(ac);
}

That way, couple(prt1, prt2) will always be equal to couple(prt2, prt1), while the probability of a hash clash is still negligible.

4
  • 2
    finding collisions on XORed hashes is much easier than the hashes themselves. ref
    – trent.sol
    Commented Jul 20, 2022 at 20:24
  • This should work with minimal risk of collision because it is extremely difficult to generate a public key of your choice @trent.sol
    – Whiteseal
    Commented Jul 21, 2022 at 17:52
  • generating the private key for a chosen public key is not the problem here though. generating two public keys which XOR to a chosen value is. this is quite easy in comparison
    – trent.sol
    Commented Jul 21, 2022 at 18:33
  • I agree, @trent.sol. Sorting is definitely the better idea compared to XORing. However, I still stand by my original statement that the risk of a collision is still negligible. The chance of (a^b) == (a1^b1), with (a1 != a ) || (b1 != b), for single bits (i.e. 0 or 1), is exactly 50%. So the risk of rendering the exact same 256 xored bits for 2 Pubkey's 1/(2^256), considered negligible everywhere on Solana. However, it's still an additional risk that can be avoided by sorting instead of xoring. Commented Jul 21, 2022 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.