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(crypto): CRP-2597 Extend NiDkgTag with HighThresholdForKey variant #2445

Open
wants to merge 50 commits into
base: master
Choose a base branch
from

Conversation

fspreiss
Copy link
Member

@fspreiss fspreiss commented Nov 5, 2024

Extends the NiDkgTag with a new variant NiDkgTag::HighThresholdForKey that holds a MasterPublicKeyId.

Notes:

  • Makes the representation for NiDkgTag explicit with #[repr(isize)] because a #[repr(inttype)] must be provided on an enum if it has a non-unit variant with a discriminant (E0732). The representation should be the same as it was before, given that isize is the default representation for enums.

    Note that casting NiDkgTag with as, e.g., to i32 or even isize is no longer possible because "an as expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less" (see Enumeration casting and E0605).

  • The conversion impl TryFrom<i32> for NiDkgTag had to be removed, because it is no longer possible, because an i32 itself is no longer sufficient for instantiating an NiDkgTag.

    This conversion was used in two places: (1) impl TryFrom<NiDkgIdProto> for NiDkgId and (2) build_tagged_transcripts_map. There, the conversion is now implemented directly.

  • No longer Implements EnumIter for NiDkgTag because this would require a Default implementation for MasterPublicKeyId, which does not make sense, at least in production. Instead implements EnumCount.

@github-actions github-actions bot added the feat label Nov 5, 2024
@fspreiss fspreiss changed the base branch from franzstefan/CRP-2597-move-masterpublickeyid-proto-to-types-ontopof-non-copy-ni-dkg-id to franzstefan/CRP-2597-move-masterpublickeyid-proto-to-types November 6, 2024 08:38
Comment on lines 330 to 335
NiDkgTag::HighThresholdForKey(master_public_key_id) => {
error!(
log,
"Implementation error: NiDkgTag::HighThresholdForKey({master_public_key_id}) used in SetupInitialDKG for callback ID {callback_id}",
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the idea here is to reuse the transcripts_for_remote_subnets field also for xnet reshares of VetKD keys. So then we would generalize this function such that it can generate the correct ConsensusResponse, depending on whether the callback ID is for a SetupInitialDKG context or a VetKD reshare context.

For now, logging an error and linking the ticket to generalize this function (CON-1416) should be fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a TODO linking to the mentioned ticket.

Comment on lines 510 to 524
////////////////////////////////////////////////////////////////////////////////
// TODO: how to behave here? The code below is copied+adapted from the HighThreshold case. However,
// this code currently won't be executed because we iterate over TAGS, which is a const that does not
// and cannot contain an NiDkgTag::HighThresholdForKey entry
///////////////////////////////////////////////////////////////////////////////
NiDkgTag::HighThresholdForKey(master_public_key_id) => {
let resharing_transcript = reshared_transcripts
.get(&NiDkgTag::HighThresholdForKey(master_public_key_id.clone()));
(
resharing_transcript
.map(|transcript| transcript.committee.get().clone())
.unwrap_or_else(|| node_ids.clone()),
resharing_transcript.cloned(),
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the behavior is correct (maybe it could even be combined with the NiDkgTag::HighThreshold branch). We can link ticket CON-1413 above, reminding us to iterate over all vetKD keys that were requested by registry in addition to the tags in TAGS.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a TODO linking to the mentioned ticket.

Also, I combined the NiDkgTag::HighThreshold | NiDkgTag::HighThresholdForKey(_).

PTAL

Comment on lines 1227 to 1230
/////////////////////////////////////////
// TODO: check with Consensus team
NiDkgTag::HighThresholdForKey(_) => panic!("not applicable"),
/////////////////////////////////////////
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can link CON-1417 to extend this test once we have support for vet key transcripts in registry CUPs

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 1336 to 1340
/////////////////////////////////////////
// TODO: check with Consensus team
NiDkgTag::HighThresholdForKey(_) => panic!("not applicable"),
/////////////////////////////////////////
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We can link CON-1413 to extend this test once we can create local transcript configs for vetKeys that were requested by registry

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

rs/types/types/src/consensus/dkg.rs Outdated Show resolved Hide resolved
rs/types/types/src/consensus/dkg.rs Outdated Show resolved Hide resolved
Base automatically changed from franzstefan/CRP-2597-move-masterpublickeyid-proto-to-types to master November 9, 2024 22:08
Copy link
Contributor

@altkdf altkdf left a comment

Choose a reason for hiding this comment

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

Thanks @fspreiss, LGTM!

@@ -115,20 +125,21 @@ impl ThresholdSigDataStoreImpl {
///
/// # Panics
/// If `max_num_of_dkg_ids_per_tag` is smaller than 1.
fn new_with_max_size(max_num_of_dkg_ids_per_tag: usize) -> Self {
fn new_with_max_size(max_num_of_dkg_ids_per_tag_or_key: usize) -> Self {
Copy link
Contributor

Choose a reason for hiding this comment

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

off-topic: Seems new is the only caller of new_with_max_size. I'm wondering if we want to eventually simplify this by inlining new_with_max_size and adding a static assert on CAPACITY_FOR_TAG to avoid having the runtime panic. But this is not a concern for this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, sure, sounds good. Did you mean to use static_assertions for this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Either that or just

const _: () = assert!(...);

@@ -294,6 +294,9 @@ fn registry_with_ni_dkg_transcript(
cup_contents.initial_ni_dkg_transcript_low_threshold =
Some(InitialNiDkgTranscriptRecord::from(transcript()));
}
NiDkgTag::HighThresholdForKey(_master_public_key_id) => {
unimplemented!("not supported currently")
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this not supported? Is this is only testing NIDKG for consensus by definition, if yes it would be better to make it explicit in the error message.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do I understand correctly, these transcripts should go into the ChainKeyInitialization introduced with #2337? Then this should already be possible, now that the PR is merged.

Copy link
Member Author

Choose a reason for hiding this comment

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

TL;DR: The tests in which the registry_with_ni_dkg_transcript helper is used will never be extended so that a NiDkgTag::HighThresholdForKey is needed, which is why this is unimplemented.

Background

This helper function, registry_with_ni_dkg_transcript, is used in two tests:

  1. should_correctly_retrieve_initial_low_threshold_ni_dkg_transcript_from_registry
  2. should_correctly_retrieve_initial_high_threshold_ni_dkg_transcript_from_registry

Both these tests test CryptoRegistry::get_initial_dkg_transcripts, which returns a

struct DkgTranscripts {
    low_threshold: NiDkgTranscript,
    high_threshold: NiDkgTranscript,
}

(I'm not sure why these tests actually live in ic-crypto-test-utils-ni-dkg. I'd say the correct place would be ic-registry-client-helpers; we should probably move the tests).

These are the two initial NiDkgTranscripts that a subnet needs to operate (low-threshold for random beacon/tape, high-threshold for state certification). They are required by the ICP protocol itself.

The NIDKG-transcript that is created for vetKeys by means of a key re-sharing request (as part of subnet creation or subnet recovery) is not needed by a subnet to operate. Because of this, such transcripts won't be returned by CryptoRegistry::get_initial_dkg_transcripts, but whoever needs them will likely fetch the CUP and then get the transcript out of that.

Because of this, I didn't see a reason

@@ -31,18 +32,22 @@ mod tests;

/// Allows to distinguish protocol executions in high and low threshold
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be worth adding what the new variant means, i.e., what is the Key and what is its relation to an NIDKG tag.

Copy link
Contributor

@maksymar maksymar left a comment

Choose a reason for hiding this comment

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

LGTM for management_canister_types

Comment on lines +75 to +76
1 => Ok(NiDkgTag::LowThreshold),
2 => Ok(NiDkgTag::HighThreshold),
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we return an error if the tag is LowThreshold or HighThreshold, but ni_dkg_id_proto.key_id isn't None?

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Comment on lines +384 to +385
1 => Ok(NiDkgTag::LowThreshold),
2 => Ok(NiDkgTag::HighThreshold),
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

/////////////////////////////////////////////////////
// TODO(CON-1417): extend this test once we have support for vetKD transcripts in registry CUPs
/////////////////////////////////////////////////////
NiDkgTag::HighThresholdForKey(_) => panic!("not applicable"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe instead of panicking with the not very informative "not applicable", we use unimplemented("CON-1417"). I mean, if we were to ever hit this case (which I don't believe we will), we would know much faster whats going on

Comment on lines +75 to +76
1 => Ok(NiDkgTag::LowThreshold),
2 => Ok(NiDkgTag::HighThreshold),
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

@@ -294,6 +294,9 @@ fn registry_with_ni_dkg_transcript(
cup_contents.initial_ni_dkg_transcript_low_threshold =
Some(InitialNiDkgTranscriptRecord::from(transcript()));
}
NiDkgTag::HighThresholdForKey(_master_public_key_id) => {
unimplemented!("not supported currently")
Copy link
Contributor

Choose a reason for hiding this comment

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

Do I understand correctly, these transcripts should go into the ChainKeyInitialization introduced with #2337? Then this should already be possible, now that the PR is merged.

pub enum NiDkgTag {
LowThreshold = 1,
HighThreshold = 2,
HighThresholdForKey(MasterPublicKeyId) = 3,
Copy link
Member Author

Choose a reason for hiding this comment

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

@altkdf, @randombit: @Sawchord suggested to use a new type NiDkgMasterPublicKeyId here instead (i.e., using HighThresholdForKey(NiDkgMasterPublicKeyId) = 3,), similar to the IDkgMasterPublicKeyId that he introduced in #2445, so as to be explicit via the type system on which types of keys can be used with NiDkg (and which cannot) and at the same time be future proof.

This type could be a struct or an enum (or somewhat both): there is a discussion around it here: https://github.com/dfinity/ic/pull/2388/files#r1839804072

I think his suggestion makes sense, so I'll start working on integrating that. Please let me know if you'd prefer to keep it as is, or if you have other comments regarding this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants