Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(staking): 🎽 IdentityKey is internally represented as bytes #4151

Closed
wants to merge 1 commit into from

Conversation

cratelyn
Copy link
Contributor

@cratelyn cratelyn commented Apr 2, 2024

work in progress.

fixes #2304.

@cratelyn cratelyn self-assigned this Apr 2, 2024
@cratelyn cratelyn added this to the Sprint 3 milestone Apr 2, 2024
@cratelyn cratelyn added the A-staking Area: Design and implementation of staking and delegation label Apr 2, 2024
@cratelyn
Copy link
Contributor Author

cratelyn commented Apr 2, 2024

NB: while we should eventually move the IdentityKey type to penumbra-keys, that change is avoided for now. thus, feat(staking).

@hdevalence
Copy link
Member

NB: while we should eventually move the IdentityKey type to penumbra-keys, that change is avoided for now. thus, feat(staking).

We shouldn't do this, the identity key is staking-specific, which is why it's in the staking component. Also, since the proto lives in the staking proto package, this isn't possible without deprecating the proto type and leaving a duplicate around. So we can plan to not do it.

Comment on lines +1 to +2
// TODO(kate):
// decompressed: std::sync::OnceLock<VerificationKey<SpendAuth>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Comment on lines +26 to +31
pub struct IdentityKey {
/// The *compressed* bytes of the identity verification key.
bytes: VerificationKeyBytes<SpendAuth>,
// The *decompressed* identity verification key.
key: OnceLock<DecompressionResult>,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should just be a wrapper around the VerificationKeyBytes:

pub struct IdentityKey(pub VerificationKeyBytes<SpendAuth>)

All we want to be doing here is replacing VerificationKey with VerificationKeyBytes, nothing more or less.

Comment on lines +82 to +89
/// Decompresses this identity key, returning a [`VerificationKey`].
///
/// This is idempotent and can be called repeatedly, and the bytes will only decompressed
/// once.
pub fn key(&self) -> Result<VerificationKey<SpendAuth>, decaf377_rdsa::Error> {
let Self { bytes, ref key } = *self;
key.get_or_init(|| VerificationKey::try_from(bytes)).clone()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be exposing this as part of the public API, it's not necessary for callers to have a convenient method for.

key: OnceLock<DecompressionResult>,
}

type DecompressionResult = Result<VerificationKey<SpendAuth>, decaf377_rdsa::Error>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to model this type separately, there should not be anywhere that needs to model it other than signature verification, which already returns an Error.

Comment on lines +49 to +79
impl From<SigningKey<SpendAuth>> for IdentityKey {
/// An [`IdentityKey`] can be constructed from a [`decaf377_rdsa::SigningKey`].
fn from(sk: SigningKey<SpendAuth>) -> Self {
let vk: VerificationKey<SpendAuth> = sk.into();
Self::from(vk)
}
}

impl<'sk> From<&'sk SigningKey<SpendAuth>> for IdentityKey {
/// An [`IdentityKey`] can be constructed from a reference to a [`decaf377_rdsa::SigningKey`].
fn from(sk: &'sk SigningKey<SpendAuth>) -> Self {
Self::from(*sk)
}
}

impl From<VerificationKey<SpendAuth>> for IdentityKey {
/// An [`IdentityKey`] can be constructed from a [`decaf377_rdsa::VerificationKey`].
fn from(vk: VerificationKey<SpendAuth>) -> Self {
let bytes: VerificationKeyBytes<SpendAuth> = vk.into();
let key: OnceLock<_> = Ok(vk).into();

Self { bytes, key }
}
}

impl<'vk> From<&'vk VerificationKey<SpendAuth>> for IdentityKey {
/// An [`IdentityKey`] can be constructed from a reference to a [`decaf377_rdsa::VerificationKey`].
fn from(vk: &'vk VerificationKey<SpendAuth>) -> Self {
Self::from(*vk)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's desirable to have all of these impls. We didn't have them before, do we need them to change the internal representation?

Comment on lines +147 to +164

impl TryFrom<Vec<u8>> for IdentityKey {
type Error = anyhow::Error;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(bytes.as_slice())
}
}

impl TryFrom<&[u8]> for IdentityKey {
type Error = anyhow::Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
bytes
.try_into()
.map(|bytes| Self {
bytes,
key: OnceLock::new(),
})
.map_err(Into::into)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid adding any new impls of TryFrom for slices or Vecs; these are an antipattern that encourages users of the API to choose their own serialization format rather than running through the protobuf changes. We don't need to add these to change the internal representation.

Copy link
Member

@hdevalence hdevalence left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a lot of code changes beyond the scope of the issue, which is changing VerificationKey to VerificationKeyBytes.

@erwanor
Copy link
Member

erwanor commented Apr 3, 2024

We shouldn't do this, the identity key is staking-specific, which is why it's in the staking component. Also, since the proto lives in the staking proto package, this isn't possible without deprecating the proto type and leaving a duplicate around. So we can plan to not do it.

@hdevalence The IdentityKey proto definition already lives in core.keys so the current situation is a bit awkward fwiw

@hdevalence
Copy link
Member

hdevalence commented Apr 3, 2024

Ah OK, in that case we should align it with the protos at some point.

@cratelyn
Copy link
Contributor Author

cratelyn commented Apr 3, 2024

this was an exploratory draft, and was not intended or ready to be reviewed. i'm going to close this in favor of #4152.

@cratelyn cratelyn closed this Apr 3, 2024
@cratelyn cratelyn deleted the kate/identity-key-bytes branch April 3, 2024 21:28
@cratelyn
Copy link
Contributor Author

cratelyn commented Apr 3, 2024

NB: while we should eventually move the IdentityKey type to penumbra-keys, that change is avoided for now. thus, feat(staking).

it seems we came to agreement on this point. i'll file an issue about it sometime this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-staking Area: Design and implementation of staking and delegation
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Change the IdentityKey domain type to store bytes rather than a decoded group element.
3 participants