grin/wallet/src/libtx/aggsig.rs

148 lines
4.1 KiB
Rust
Raw Normal View History

// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Aggsig helper functions used in transaction creation.. should be only
//! interface into the underlying secp library
use keychain::blind::BlindingFactor;
use keychain::extkey::Identifier;
Minimal Transaction Pool (#1067) * verify a tx like we verify a block (experimental) * first minimal_pool test up and running but not testing what we need to * rework tx_pool validation to use txhashset extension * minimal tx pool wired up but rough * works locally (rough statew though) delete "legacy" pool and graph code * rework the new pool into TransactionPool and Pool impls * rework pool to store pool entries with associated timer and source etc. * all_transactions * extra_txs so we can validate stempool against existing txpool * rework reconcile_block * txhashset apply_raw_tx can now rewind to a checkpoint (prev raw tx) * wip - txhashset tx tests * more flexible rewind on MMRs * add tests to cover apply_raw_txs on txhashset extension * add_to_stempool and add_to_txpool * deaggregate multi kernel tx when adding to txpoool * handle freshness in stempool handle propagation of stempool txs via dandelion monitor * patience timer and fluff if we cannot propagate to next relay * aggregate and fluff stempool is we have no relay * refactor coinbase maturity * rewrote basic tx pool tests to use a real txhashset via chain adapter * rework dandelion monitor to reflect recent discussion works locally but needs a cleanup * refactor dandelion_monitor - split out phases * more pool test coverage * remove old test code from pool (still wip) * block_building and block_reconciliation tests * tracked down chain test failure... * fix test_coinbase_maturity * dandelion_monitor now runs... * refactor dandelion config, shared across p2p and pool components * fix pool tests with new config * fix p2p tests * rework tx pool to deal with duplicate commitments (testnet2 limitation) * cleanup and address some PR feedback * add big comment about pre_tx...
2018-05-30 23:57:13 +03:00
use keychain::Keychain;
use libtx::error::Error;
use util::kernel_sig_msg;
use util::secp::key::{PublicKey, SecretKey};
use util::secp::pedersen::Commitment;
use util::secp::{self, aggsig, Message, Secp256k1, Signature};
/// exports a secure nonce guaranteed to be usable
/// in aggsig creation
pub fn create_secnonce(secp: &Secp256k1) -> Result<SecretKey, Error> {
let nonce = aggsig::export_secnonce_single(secp)?;
Ok(nonce)
}
/// Calculate a partial sig
pub fn calculate_partial_sig(
secp: &Secp256k1,
sec_key: &SecretKey,
sec_nonce: &SecretKey,
nonce_sum: &PublicKey,
fee: u64,
lock_height: u64,
) -> Result<Signature, Error> {
// Add public nonces kR*G + kS*G
let msg = secp::Message::from_slice(&kernel_sig_msg(fee, lock_height))?;
//Now calculate signature using message M=fee, nonce in e=nonce_sum
let sig = aggsig::sign_single(
secp,
&msg,
sec_key,
Some(sec_nonce),
Some(nonce_sum),
Some(nonce_sum),
)?;
Ok(sig)
}
/// Verifies a partial sig given all public nonces used in the round
pub fn verify_partial_sig(
secp: &Secp256k1,
sig: &Signature,
pub_nonce_sum: &PublicKey,
pubkey: &PublicKey,
fee: u64,
lock_height: u64,
) -> Result<(), Error> {
let msg = secp::Message::from_slice(&kernel_sig_msg(fee, lock_height))?;
if !verify_single(secp, sig, &msg, Some(&pub_nonce_sum), pubkey, true) {
return Err(Error::Signature("Signature validation error".to_string()));
}
Ok(())
}
/// Just a simple sig, creates its own nonce, etc
pub fn sign_from_key_id(
secp: &Secp256k1,
k: &Keychain,
msg: &Message,
key_id: &Identifier,
) -> Result<Signature, Error> {
let skey = k.derived_key(key_id)?;
let sig = aggsig::sign_single(secp, &msg, &skey, None, None, None)?;
Ok(sig)
}
/// Verifies a sig given a commitment
pub fn verify_single_from_commit(
secp: &Secp256k1,
sig: &Signature,
msg: &Message,
commit: &Commitment,
) -> Result<(), Error> {
// Extract the pubkey, unfortunately we need this hack for now, (we just hope
// one is valid)
let pubkey = commit.to_pubkey(secp)?;
if !verify_single(secp, sig, &msg, None, &pubkey, false) {
return Err(Error::Signature("Signature validation error".to_string()));
}
Ok(())
}
/// Verify a sig, with built message
pub fn verify_sig_build_msg(
secp: &Secp256k1,
sig: &Signature,
pubkey: &PublicKey,
fee: u64,
lock_height: u64,
) -> Result<(), Error> {
let msg = secp::Message::from_slice(&kernel_sig_msg(fee, lock_height))?;
if !verify_single(secp, sig, &msg, None, pubkey, true) {
return Err(Error::Signature("Signature validation error".to_string()));
}
Ok(())
}
/// Verifies an aggsig signature
pub fn verify_single(
secp: &Secp256k1,
sig: &Signature,
msg: &Message,
pubnonce: Option<&PublicKey>,
pubkey: &PublicKey,
is_partial: bool,
) -> bool {
aggsig::verify_single(secp, sig, msg, pubnonce, pubkey, is_partial)
}
/// Adds signatures
pub fn add_signatures(
secp: &Secp256k1,
part_sigs: Vec<&Signature>,
nonce_sum: &PublicKey,
) -> Result<Signature, Error> {
// Add public nonces kR*G + kS*G
let sig = aggsig::add_signatures_single(&secp, part_sigs, &nonce_sum)?;
Ok(sig)
}
/// Just a simple sig, creates its own nonce, etc
pub fn sign_with_blinding(
secp: &Secp256k1,
msg: &Message,
blinding: &BlindingFactor,
) -> Result<Signature, Error> {
let skey = &blinding.secret_key(&secp)?;
let sig = aggsig::sign_single(secp, &msg, skey, None, None, None)?;
Ok(sig)
}