diff --git a/wallet/src/libtx/aggsig.rs b/wallet/src/libtx/aggsig.rs index 5efecefcc..f00bc6ee6 100644 --- a/wallet/src/libtx/aggsig.rs +++ b/wallet/src/libtx/aggsig.rs @@ -130,7 +130,6 @@ pub fn calculate_partial_sig( /// * `pub_nonce_sum` - The sum of the public nonces of all signers participating /// in the full signature. This value is encoded in e. /// * `pubkey` - Corresponding Public Key of the private key used to sign the message. -/// was added to the `nonce_sum` total) /// * `pubkey_sum` - (Optional) The sum of the public keys of all signers participating /// in the full signature. If included, this value is encoded in e. /// * `msg` - The message to verify. @@ -203,7 +202,59 @@ pub fn verify_partial_sig( Ok(()) } -/// Just a simple sig, creates its own nonce, etc +/// Creates a single-signer aggsig signature from a key id. Generally, +/// this function is used to create transaction kernel signatures for +/// coinbase outputs. +/// Returns `Ok(Signature)` if the signature is valid, or a Signature +/// [ErrorKind](../enum.ErrorKind.html) otherwise +/// +/// # Arguments +/// +/// * `secp` - A Secp256k1 Context initialized for Signing +/// * `k` - The Keychain implementation being used +/// * `msg` - The message to sign (fee|lockheight). +/// * `key_id` - The keychain key id corresponding to the private key +/// with which to sign the message +/// * `blind_sum` - (Optional) The sum of all blinding factors in the transaction +/// in the case of a coinbase transaction this will simply be the corresponding +/// public key. +/// +/// # Example +/// +/// ``` +/// # extern crate grin_util as util; +/// # extern crate grin_core as core; +/// # extern crate grin_wallet as wallet; +/// # extern crate grin_keychain as keychain; +/// use core::consensus::reward; +/// use wallet::libtx::{aggsig, proof}; +/// use util::secp::key::{PublicKey, SecretKey}; +/// use util::secp::{ContextFlag, Secp256k1}; +/// use core::core::transaction::kernel_sig_msg; +/// use core::core::{Output, OutputFeatures}; +/// use keychain::{Keychain, ExtKeychain}; +/// +/// let secp = Secp256k1::with_caps(ContextFlag::Commit); +/// let keychain = ExtKeychain::from_random_seed().unwrap(); +/// let fees = 10_000; +/// let value = reward(fees); +/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); +/// let commit = keychain.commit(value, &key_id).unwrap(); +/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap(); +/// let output = Output { +/// features: OutputFeatures::COINBASE_OUTPUT, +/// commit: commit, +/// proof: rproof, +/// }; +/// let height = 20; +/// let over_commit = secp.commit_value(reward(fees)).unwrap(); +/// let out_commit = output.commitment(); +/// let msg = kernel_sig_msg(0, height).unwrap(); +/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap(); +/// let pubkey = excess.to_pubkey(&secp).unwrap(); +/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, &key_id, Some(&pubkey)).unwrap(); +/// ``` + pub fn sign_from_key_id( secp: &Secp256k1, k: &K, @@ -228,7 +279,61 @@ where Ok(sig) } -/// Verifies a sig given a commitment +/// Simple verification a single signature from a commitment. The public +/// key used to verify the signature is derived from the commit. +/// Returns `Ok(())` if the signature is valid, or a Signature +/// [ErrorKind](../enum.ErrorKind.html) otherwise +/// +/// # Arguments +/// +/// * `secp` - A Secp256k1 Context initialized for Verification +/// * `sig` - The Signature to verify +/// * `msg` - The message to sign (fee|lockheight). +/// * `commit` - The commitment to verify. The actual public key used +/// during verification is derived from this commit. +/// +/// # Example +/// +/// ``` +/// # extern crate grin_util as util; +/// # extern crate grin_core as core; +/// # extern crate grin_wallet as wallet; +/// # extern crate grin_keychain as keychain; +/// use core::consensus::reward; +/// use wallet::libtx::{aggsig, proof}; +/// use util::secp::key::{PublicKey, SecretKey}; +/// use util::secp::{ContextFlag, Secp256k1}; +/// use core::core::transaction::kernel_sig_msg; +/// use core::core::{Output, OutputFeatures}; +/// use keychain::{Keychain, ExtKeychain}; +/// +/// // Create signature +/// let secp = Secp256k1::with_caps(ContextFlag::Commit); +/// let keychain = ExtKeychain::from_random_seed().unwrap(); +/// let fees = 10_000; +/// let value = reward(fees); +/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); +/// let commit = keychain.commit(value, &key_id).unwrap(); +/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap(); +/// let output = Output { +/// features: OutputFeatures::COINBASE_OUTPUT, +/// commit: commit, +/// proof: rproof, +/// }; +/// let height = 20; +/// let over_commit = secp.commit_value(reward(fees)).unwrap(); +/// let out_commit = output.commitment(); +/// let msg = kernel_sig_msg(0, height).unwrap(); +/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap(); +/// let pubkey = excess.to_pubkey(&secp).unwrap(); +/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, &key_id, Some(&pubkey)).unwrap(); +/// +/// // Verify the signature from the excess commit +/// let sig_verifies = +/// aggsig::verify_single_from_commit(&keychain.secp(), &sig, &msg, &excess); +/// assert!(!sig_verifies.is_err()); +/// ``` + pub fn verify_single_from_commit( secp: &Secp256k1, sig: &Signature, @@ -244,8 +349,63 @@ pub fn verify_single_from_commit( Ok(()) } -/// Verify a sig, with built message -pub fn verify_sig_build_msg( +/// Verifies a completed (summed) signature, which must include the message +/// and pubkey sum values that are used during signature creation time +/// to create 'e' +/// Returns `Ok(())` if the signature is valid, or a Signature +/// [ErrorKind](../enum.ErrorKind.html) otherwise +/// +/// # Arguments +/// +/// * `secp` - A Secp256k1 Context initialized for Verification +/// * `sig` - The Signature to verify +/// * `pubkey` - Corresponding Public Key of the private key used to sign the message. +/// * `pubkey_sum` - (Optional) The sum of the public keys of all signers participating +/// in the full signature. If included, this value is encoded in e. Must be the same +/// value as when the signature was created to verify correctly. +/// * `msg` - The message to verify (fee|lockheight). +/// +/// # Example +/// +/// ``` +/// # extern crate grin_util as util; +/// # extern crate grin_wallet as wallet; +/// # extern crate rand; +/// use rand::thread_rng; +/// use wallet::libtx::aggsig; +/// use util::secp::key::{PublicKey, SecretKey}; +/// use util::secp::{ContextFlag, Secp256k1, Message}; +/// +/// let secp = Secp256k1::with_caps(ContextFlag::Full); +/// let secret_nonce = aggsig::create_secnonce(&secp).unwrap(); +/// let secret_key = SecretKey::new(&secp, &mut thread_rng()); +/// let pub_nonce_sum = PublicKey::from_secret_key(&secp, &secret_nonce).unwrap(); +/// // ... Add all other participating nonces +/// let pub_key_sum = PublicKey::from_secret_key(&secp, &secret_key).unwrap(); +/// // ... Add all other participating keys +/// let mut msg_bytes = [0; 32]; +/// // ... Encode message +/// let message = Message::from_slice(&msg_bytes).unwrap(); +/// let sig_part = aggsig::calculate_partial_sig( +/// &secp, +/// &secret_key, +/// &secret_nonce, +/// &pub_nonce_sum, +/// Some(&pub_key_sum), +/// &message, +/// ).unwrap(); +/// // ... Verify above, once all signatures have been added together +/// let sig_verifies = aggsig::verify_completed_sig( +/// &secp, +/// &sig_part, +/// &pub_key_sum, +/// Some(&pub_key_sum), +/// &message, +/// ); +/// assert!(!sig_verifies.is_err()); +/// ``` + +pub fn verify_completed_sig( secp: &Secp256k1, sig: &Signature, pubkey: &PublicKey, diff --git a/wallet/src/libtx/slate.rs b/wallet/src/libtx/slate.rs index c00414eae..6dc5c4095 100644 --- a/wallet/src/libtx/slate.rs +++ b/wallet/src/libtx/slate.rs @@ -353,7 +353,7 @@ impl Slate { // Calculate the final public key (for our own sanity check) // Check our final sig verifies - aggsig::verify_sig_build_msg( + aggsig::verify_completed_sig( &keychain.secp(), &final_sig, &final_pubkey, diff --git a/wallet/tests/libwallet.rs b/wallet/tests/libwallet.rs index fbea595e1..c7d1dc956 100644 --- a/wallet/tests/libwallet.rs +++ b/wallet/tests/libwallet.rs @@ -205,7 +205,7 @@ fn aggsig_sender_receiver_interaction() { let msg = kernel_sig_msg(0, 0).unwrap(); // Receiver check the final signature verifies - let sig_verifies = aggsig::verify_sig_build_msg( + let sig_verifies = aggsig::verify_completed_sig( &keychain.secp(), &final_sig, &final_pubkey, @@ -411,7 +411,7 @@ fn aggsig_sender_receiver_interaction_offset() { let msg = kernel_sig_msg(0, 0).unwrap(); // Receiver check the final signature verifies - let sig_verifies = aggsig::verify_sig_build_msg( + let sig_verifies = aggsig::verify_completed_sig( &keychain.secp(), &final_sig, &final_pubkey,