Trait bound Eq is not satified

Please, what does this mean?

The trait bound ed25519_dalek::SecretKey: Eq is not satisfied
required because of the requirements on the impl of Eq for Option<ed25519_dalek::SecretKey>

use secp256k1::{PublicKey, Secp256k1, SecretKey, SignOnly, VerifyOnly};
use ed25519_dalek::{SecretKey as EdDsaSecretKey};

lazy_static! {
    static ref SECP256K1_SIGN_ONLY: Secp256k1<SignOnly> = Secp256k1::signing_only();
    static ref SECP256K1_VERIFY_ONLY: Secp256k1<VerifyOnly> = Secp256k1::verification_only();
}

type ChainCode = Vec<u8>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtendedPrivKey {
    pub private_key: Option<SecretKey>,
    pub chain_code: ChainCode,
    pub ed_dsa_private_key: Option<EdDsaSecretKey> <- Here
}

derive(PartialEq, Eq) will automatically generate code that should run when you compare two values x: ExtendPrivKey and y: ExtendPrivKey via x == y operation. The generated code will check equality on all fields, e.g. x.private_key == y.private_key && x.chain_code == y.chain_code && x.ed_dsa_private_key == y.ed_dsa_private_key. For this to work, the types of these fields need to support ==-comparison, too.

The (PartialEq and) Eq trait is the way Rust codifies the notion of whether or not values of a type can be compared using ==. Looking at the documentation ( ed25519_dalek::SecretKey - Rust ) you can see that the trait implementations section does not feature PartialEq/Eq, which means values of type ed25519_dalek::SecretKey cannot be compared using ==.

Now, it’s up to you to decide whether comparing such values for whether or not they’re “equal” might make sense anyway; or whether ExtendedPrivKey should be considered equal under some different condition that doesn’t involve comparing their ed_dsa_private_key fields; or whether ==-operator support for ExtendedPrivKey is not needed after all. In the first two cases, you can write a manual PartialEq implementation for ExtendedPrivKey (you can still derive Eq because it itself doesn’t actually feature any methods), in the last case, you simply remove the two traits PartialEq and Eq from the derive list alltogether.

A manual implementation of PartialEq would look like

impl PartialEq for ExtendedPrivKey {
    fn eq(&self, other: &Self) -> bool {
        todo!() // <- your code here, comparing `self` and `other`
    }
}

I’ve kind-of skipped over the Option in the explanation above, but it doesn’t matter much because Option<T> supports == precisely if T supports ==.

Note that ed25519_dalek::SecretKey values can be compared with key1.as_bytes() == key2.as_bytes(), so you could implement PartialEq manually using that. However, there could be an important cryptographic reason why ed25519_dalek::SecretKey doesn't implement PartialEq; I'm not an expert, but it could enable timing attacks to guess the value of the private key in certain circumstances.

Thanks for your response, It doesn't seem to work

binary operation `==` cannot be applied to type `Option<ed25519_dalek::SecretKey>`
pub struct ExtendedPrivKey {
    pub private_key: Option<SecretKey>,
    pub chain_code: ChainCode,
    pub ed_dsa_private_key: Option<ed25519_dalek::SecretKey>,
}

impl PartialEq for ExtendedPrivKey {
    fn eq(&self, other: &Self) -> bool {
        self.private_key == other.private_key && self.chain_code == other.chain_code && self.ed_dsa_private_key == other.ed_dsa_private_key
    }
}

Thanks, @LegionMammal978, for your response, I tried that, but it didn't work.

the trait bound `ed25519_dalek::SecretKey: Eq` is not satisfied
required because of the requirements on the impl of `Eq` for `Option<ed25519_dalek::SecretKey>`
#[derive(Debug, Clone, Eq)]
pub struct ExtendedPrivKey {
    pub private_key: Option<SecretKey>,
    pub chain_code: ChainCode,
    pub ed_dsa_private_key: Option<ed25519_dalek::SecretKey>,
}

impl PartialEq for ExtendedPrivKey {
    fn eq(&self, other: &Self) -> bool {
        self.private_key == other.private_key && self.chain_code == other.chain_code && self.ed_dsa_private_key.unwrap().as_bytes() == other.ed_dsa_private_key.unwrap().as_bytes()
    }
}

Well, as I explaned above, this code

todo!() // <- your code here, comparing `self` and `other`

was meant to be filled in in order to handle the fact that

either by somehow arguing that

in which case you must invent your own notion of “equality” between ed25519_dalek::SecretKey values,

or in case


I also pointed out that

And the whole point of not using the automatically genereted implementation in this case would be because the generated one doesn’t work. Using the same code nonetheless results in the same error message, unsurprisingly.


In case this wasn’t clear, my explanations cited above mean that

  • ed25519_dalek::SecretKey does not support ==, and neither does Option<ed25519_dalek::SecretKey> so you cannot write x.ed_dsa_private_key == y.ed_dsa_private_key
  • in case you know some way of comparing two values of type ed25519_dalek::SecretKey for equality that makes sense, you might use that anyways, e.g. the one @LegionMammal978 suggested, but of course, it might be the case that comparing SecretKeys like this might be undesirable or meaningless for whatever reason; I don’t know, but ed25519_dalek::SecretKey might not implement PartialEq/Eq for a reason
  • otherwise, you could use some implementation that doesn’t involve comparing the ed_dsa_private_key at all, in case that makes sense for your use case

Side note, try to learn posting full error messages, as reported by cargo check in the terminal. Those tend to be way easier to read than what you are posting.

With regards to

I’d assume that error appears on the derive(Eq) part, and I must say that I was incorrect on my observation that

because it turns out derive(Eq) does conservatively check if all the fields implement Eq as well (and it does have a hidden method in order for the generated code to be able to check this).

So I’ll correct myself, and you will have to also implement Eq manually after all, but that’s easy because it’s simply

impl Eq for ExtendedPrivKey {}

In case a as_bytes-based approach makes sense for your implementation, you might want to change .ed_dsa_private_key.unwrap().as_bytes() to something along the lines of .ed_dsa_private_key().as_ref().map(EdDsaSecretKey::as_bytes).

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.