Skip to content

Commit

Permalink
feat(crypto): CRP-2445 add threshold Schnorr traits and structs
Browse files Browse the repository at this point in the history
  • Loading branch information
altkdf committed Mar 19, 2024
1 parent 69a796c commit aba6984
Show file tree
Hide file tree
Showing 4 changed files with 765 additions and 31 deletions.
115 changes: 113 additions & 2 deletions rs/interfaces/src/crypto/sign/canister_threshold_sig.rs
Expand Up @@ -36,14 +36,17 @@ use ic_types::crypto::canister_threshold_sig::error::{
IDkgVerifyDealingPrivateError, IDkgVerifyDealingPublicError, IDkgVerifyInitialDealingsError,
IDkgVerifyOpeningError, IDkgVerifyTranscriptError, ThresholdEcdsaCombineSigSharesError,
ThresholdEcdsaSignShareError, ThresholdEcdsaVerifyCombinedSignatureError,
ThresholdEcdsaVerifySigShareError,
ThresholdEcdsaVerifySigShareError, ThresholdSchnorrCombineSigSharesError,
ThresholdSchnorrCreateSigShareError, ThresholdSchnorrVerifyCombinedSigError,
ThresholdSchnorrVerifySigShareError,
};
use ic_types::crypto::canister_threshold_sig::idkg::{
BatchSignedIDkgDealings, IDkgComplaint, IDkgOpening, IDkgTranscript, IDkgTranscriptParams,
InitialIDkgDealings, SignedIDkgDealing,
};
use ic_types::crypto::canister_threshold_sig::{
ThresholdEcdsaCombinedSignature, ThresholdEcdsaSigInputs, ThresholdEcdsaSigShare,
ThresholdSchnorrCombinedSignature, ThresholdSchnorrSigInputs, ThresholdSchnorrSigShare,
};
use std::collections::{BTreeMap, HashSet};

Expand Down Expand Up @@ -519,7 +522,7 @@ pub trait IDkgProtocol {
) -> Result<(), IDkgRetainKeysError>;
}

/// A Crypto Component interface to generate ECDSA threshold signature shares during the
/// A Crypto Component interface to generate threshold ECDSA signature shares during the
/// online phase of the threshold ECDSA protocol. During the offline phase, nodes precompute
/// quadruples of IDKG transcripts. Each of these quadruples is then used by the nodes to
/// reply to a single signing request, and then it is discarded.
Expand Down Expand Up @@ -573,6 +576,8 @@ pub trait ThresholdEcdsaSigVerifier {
/// valid.
/// * [`ThresholdEcdsaVerifySigShareError::InvalidArgumentMissingSignerInTranscript`] if the signer
/// was not eligible according to the key transcript.
/// * [`ThresholdEcdsaVerifySigShareError::InvalidArguments`] if some arguments are invalid, e.g.,
/// wrong algorithm id.
fn verify_sig_share(
&self,
signer: NodeId,
Expand Down Expand Up @@ -609,9 +614,115 @@ pub trait ThresholdEcdsaSigVerifier {
/// * [`ThresholdEcdsaVerifyCombinedSignatureError::InvalidSignature`] if the signature is not valid.
/// * [`ThresholdEcdsaVerifyCombinedSignatureError::SerializationError`] if there was an error deserializing the
/// transcripts or the signature.
/// * [`ThresholdEcdsaVerifyCombinedSignatureError::InvalidArguments`] if some arguments are invalid, e.g.,
/// wrong algorithm id.
fn verify_combined_sig(
&self,
inputs: &ThresholdEcdsaSigInputs,
signature: &ThresholdEcdsaCombinedSignature,
) -> Result<(), ThresholdEcdsaVerifyCombinedSignatureError>;
}

/// A Crypto Component interface to generate threshold Schnorr signature shares during the
/// online phase of the threshold Schnorr protocol. During the offline phase, nodes precompute
/// presignature IDKG transcripts. Each of these presignatures is then used by the nodes to
/// reply to a single signing request, and then the presignature is discarded.
///
/// # Protocol Overview:
/// The threshold signing protocol is non-interactive, which means that the nodes participating
/// to the protocol only need to compute a signature share and publish it. Shares can then be
/// publicly verified by anybody and combined into a single Schnorr signature.
pub trait ThresholdSchnorrSigner {
/// Create a threshold Schnorr signature share.
///
/// # Prerequisites
/// This method depends on the key material for the IDKG transcripts specified in
/// `ThresholdSchnorrSigInputs` to be present in the canister secret key store of the
/// crypto component. To initialize this key material the transcripts must be loaded
/// using the method [`IDkgProtocol::load_transcript`].
///
/// # Errors
/// * [`ThresholdSchnorrSigShareError::InternalError`] if there was an internal error creating the
/// signature share, likely due to invalid input.
/// * [`ThresholdSchnorrSigShareError::NotAReceiver`] if the caller isn't in the
/// transcripts' receivers. Only receivers can create signature shares.
/// * [`ThresholdSchnorrSigShareError::SerializationError`] if there was an error deserializing the
/// transcripts or serializing the signature share.
/// * [`ThresholdSchnorrSigShareError::SecretSharesNotFound`] if the secret shares necessary
/// for creating the dealing could not be found in the canister secret key store. Calling
/// [`IDkgProtocol::load_transcript`] may be necessary.
/// * [`ThresholdSchnorrSigShareError::TransientInternalError`] if there was a transient internal
/// error, e.g., when communicating with the remote vault.
fn create_sig_share(
&self,
inputs: &ThresholdSchnorrSigInputs,
) -> Result<ThresholdSchnorrSigShare, ThresholdSchnorrCreateSigShareError>;
}

/// A Crypto Component interface to perform public operations during the online phase of the
/// threshold Schnorr protocol. During the online phase, nodes compute and advertise shares of
/// the signatures. These interfaces can be used to verify the shares, combine them into a
/// single Schnorr signature, and verify the combined signature. All these operations can be
/// performed publicly and do not require private information.
pub trait ThresholdSchnorrSigVerifier {
/// Verify a threshold Schnorr signature share.
///
/// # Errors
/// * [`ThresholdSchnorrVerifySigShareError::InternalError`] if there was an internal error while
/// verifying the signature share, likely due to invalid input.
/// * [`ThresholdSchnorrVerifySigShareError::SerializationError`] if there was an error deserializing the
/// transcripts or the signature share.
/// * [`ThresholdSchnorrVerifySigShareError::InvalidSignatureShare`] if the signature share is not
/// valid.
/// * [`ThresholdSchnorrVerifySigShareError::InvalidArgumentMissingSignerInTranscript`] if the signer
/// was not eligible according to the key transcript.
/// * [`ThresholdSchnorrVerifySigShareError::InvalidArguments`] if some arguments are invalid, e.g.,
/// wrong algorithm id.
fn verify_sig_share(
&self,
signer: NodeId,
inputs: &ThresholdSchnorrSigInputs,
share: &ThresholdSchnorrSigShare,
) -> Result<(), ThresholdSchnorrVerifySigShareError>;

/// Combine the given threshold Schnorr signature shares into a conventional Schnorr signature.
///
/// The signature is returned as raw bytes.
///
/// # Errors
/// * [`ThresholdSchnorrCombineSigSharesError::InternalError`] if there was an internal error while
/// combining the signature shares, likely due to invalid input.
/// * [`ThresholdSchnorrCombineSigSharesError::UnsatisfiedReconstructionThreshold`] if the number
/// of signature shares was not sufficient to reconstruct a Schnorr signature.
/// * [`ThresholdSchnorrCombineSigSharesError::SerializationError`] if there was an error deserializing the
/// transcripts or the signature shares.
/// * [`ThresholdSchnorrCombineSigSharesError::SignerNotAllowed`] if one or more of the singers were
/// not eligible according to the key transcript.
fn combine_sig_shares(
&self,
inputs: ThresholdSchnorrSigInputs,
shares: &BTreeMap<NodeId, ThresholdSchnorrSigShare>,
) -> Result<ThresholdSchnorrCombinedSignature, ThresholdSchnorrCombineSigSharesError>;

/// Verify a combined Schnorr signature and its consistency with the input.
/// In particular, it verifies that the signature is computed from the
/// presignature transcript, which is computed in the offline phase of the
/// protocol. This helps ensuring each instance of the signing protocol
/// computes fresh signatures.
///
/// # Errors
/// * [`ThresholdSchnorrVerifyCombinedSigError::InternalError`] if
/// there was an internal error while verifying the combined signature,
/// likely due to invalid input.
/// * [`ThresholdSchnorrVerifyCombinedSigError::InvalidSignature`] if
/// the signature is not valid.
/// * [`ThresholdSchnorrVerifyCombinedSigError::SerializationError`]
/// if there was an error deserializing the transcripts or the signature.
/// * [`ThresholdSchnorrVerifyCombinedSigError::InvalidArguments`] if
/// some arguments were invalid, e.g., wrong algorithm ID.
fn verify_combined_sig(
&self,
inputs: &ThresholdSchnorrSigInputs,
signature: &ThresholdSchnorrCombinedSignature,
) -> Result<(), ThresholdSchnorrVerifyCombinedSigError>;
}

0 comments on commit aba6984

Please sign in to comment.