diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 4fedb62ff..929d4541a 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -23,6 +23,7 @@ use std::time::{Duration, Instant}; use core::core::hash::{Hash, Hashed}; use core::core::pmmr::MerkleProof; use core::core::target::Difficulty; +use core::core::Committed; use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel}; use core::global; use grin_store::Error::NotFoundErr; @@ -200,7 +201,14 @@ impl Chain { header.height, header.hash() ); - let (output_sum, kernel_sum) = extension.validate_sums(&header)?; + + let (output_sum, kernel_sum) = extension.verify_kernel_sums( + header.total_overage(), + header.total_kernel_offset(), + None, + None, + )?; + store.save_block_sums( &header.hash(), &BlockSums { diff --git a/chain/src/txhashset.rs b/chain/src/txhashset.rs index 2081a01d5..f11152eeb 100644 --- a/chain/src/txhashset.rs +++ b/chain/src/txhashset.rs @@ -24,11 +24,11 @@ use std::time::Instant; use util::secp::pedersen::{Commitment, RangeProof}; -use core::consensus::REWARD; +use core::core::committed::Committed; use core::core::hash::{Hash, Hashed}; use core::core::pmmr::{self, MerkleProof, PMMR}; -use core::core::{Block, BlockHeader, Committed, Input, Output, OutputFeatures, OutputIdentifier, - Transaction, TxKernel}; +use core::core::{Block, BlockHeader, Input, Output, OutputFeatures, OutputIdentifier, Transaction, + TxKernel}; use core::global; use core::ser::{PMMRIndexHashable, PMMRable}; @@ -773,35 +773,6 @@ impl<'a> Extension<'a> { Ok(()) } - /// The real magicking: the sum of all kernel excess should equal the sum - /// of all output commitments, minus the total supply. - pub fn validate_sums(&self, header: &BlockHeader) -> Result<((Commitment, Commitment)), Error> { - let now = Instant::now(); - - // Treat the total "supply" as one huge overage that needs to be accounted for. - // If we have a supply of 6,000 grin then we should - // have a corresponding 6,000 grin in unspent outputs. - let supply = ((header.height * REWARD) as i64).checked_neg().unwrap_or(0); - let output_sum = self.sum_commitments(supply, None)?; - - let (kernel_sum, kernel_sum_plus_offset) = - self.sum_kernel_excesses(&header.total_kernel_offset, None)?; - - if output_sum != kernel_sum_plus_offset { - return Err(Error::InvalidTxHashSet( - "Differing Output commitment and kernel excess sums.".to_owned(), - )); - } - - debug!( - LOGGER, - "txhashset: validated sums, took (total) {}s", - now.elapsed().as_secs(), - ); - - Ok((output_sum, kernel_sum)) - } - /// Validate the txhashset state against the provided block header. pub fn validate( &mut self, @@ -816,13 +787,21 @@ impl<'a> Extension<'a> { return Ok((zero_commit.clone(), zero_commit.clone())); } - let (output_sum, kernel_sum) = self.validate_sums(header)?; + // The real magicking happens here. + // Sum of kernel excesses should equal sum of + // unspent outputs minus total supply. + let (output_sum, kernel_sum) = self.verify_kernel_sums( + header.total_overage(), + header.total_kernel_offset(), + None, + None, + )?; - // this is a relatively expensive verification step + // This is an expensive verification step. self.verify_kernel_signatures()?; - // verify the rangeproof for each output in the sum above - // this is an expensive operation (only verified if requested) + // Verify the rangeproof for each output in the sum above. + // This is an expensive verification step (skip for faster verification). if !skip_rproofs { self.verify_rangeproofs()?; } diff --git a/chain/src/types.rs b/chain/src/types.rs index 7f65cc4f3..6fc862bed 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -20,6 +20,7 @@ use util::secp; use util::secp::pedersen::Commitment; use util::secp_static; +use core::core::committed; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; use core::core::{block, transaction, Block, BlockHeader}; @@ -107,6 +108,8 @@ pub enum Error { Transaction(transaction::Error), /// Anything else Other(String), + /// Error from summing and verifying kernel sums via committed trait. + Committed(committed::Error), } impl error::Error for Error { @@ -155,6 +158,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: committed::Error) -> Error { + Error::Committed(e) + } +} + impl Error { /// Whether the error is due to a block that was intrinsically wrong pub fn is_bad_data(&self) -> bool { diff --git a/core/src/core/block.rs b/core/src/core/block.rs index f41e88bd2..fea0ee1f7 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -21,12 +21,14 @@ use time; use consensus; use consensus::{exceeds_weight, reward, VerifySortOrder, REWARD}; +use core::committed; +use core::committed::Committed; use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH}; use core::id::ShortIdentifiable; use core::target::Difficulty; use core::transaction; -use core::{Commitment, Committed, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId, - Transaction, TxKernel}; +use core::{Commitment, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId, Transaction, + TxKernel}; use global; use keychain; use keychain::BlindingFactor; @@ -66,10 +68,18 @@ pub enum Error { }, /// Underlying Merkle proof error MerkleProof, + /// Error when verifying kernel sums via committed trait. + Committed(committed::Error), /// Other unspecified error condition Other(String), } +impl From for Error { + fn from(e: committed::Error) -> Error { + Error::Committed(e) + } +} + impl From for Error { fn from(e: transaction::Error) -> Error { Error::Transaction(e) @@ -219,6 +229,23 @@ impl BlockHeader { hasher.finalize(&mut ret); Hash(ret) } + + /// The "overage" to use when verifying the kernel sums. + /// For a block header the overage is 0 - reward. + pub fn overage(&self) -> i64 { + (REWARD as i64).checked_neg().unwrap_or(0) + } + + /// The "total overage" to use when verifying the kernel sums for a full + /// chain state. For a full chain state this is 0 - (height * reward). + pub fn total_overage(&self) -> i64 { + ((self.height * REWARD) as i64).checked_neg().unwrap_or(0) + } + + /// Total kernel offset for the chain state up to and including this block. + pub fn total_kernel_offset(&self) -> BlindingFactor { + self.total_kernel_offset + } } /// Compact representation of a full block. @@ -658,7 +685,17 @@ impl Block { self.verify_coinbase()?; self.verify_inputs()?; self.verify_kernel_lock_heights()?; - self.verify_sums(prev_output_sum, prev_kernel_sum) + + let sums = self.verify_kernel_sums( + self.header.overage(), + self.header.total_kernel_offset(), + Some(prev_output_sum), + Some(prev_kernel_sum), + )?; + + self.verify_rangeproofs()?; + self.verify_kernel_signatures()?; + Ok(sums) } fn verify_weight(&self) -> Result<(), Error> { @@ -707,37 +744,22 @@ impl Block { Ok(()) } - /// Verify sums - pub fn verify_sums( - &self, - prev_output_sum: &Commitment, - prev_kernel_sum: &Commitment, - ) -> Result<((Commitment, Commitment)), Error> { - // Verify the output rangeproofs. - // Note: this is expensive. - for x in &self.outputs { - x.verify_proof()?; - } - - // Verify the kernel signatures. - // Note: this is expensive. + /// Verify the kernel signatures. + /// Note: this is expensive. + fn verify_kernel_signatures(&self) -> Result<(), Error> { for x in &self.kernels { x.verify()?; } + Ok(()) + } - // Sum all input|output|overage commitments. - let overage = (REWARD as i64).checked_neg().unwrap_or(0); - let io_sum = self.sum_commitments(overage, Some(prev_output_sum))?; - - // Sum the kernel excesses accounting for the kernel offset. - let (kernel_sum, kernel_sum_plus_offset) = - self.sum_kernel_excesses(&self.header.total_kernel_offset, Some(prev_kernel_sum))?; - - if io_sum != kernel_sum_plus_offset { - return Err(Error::KernelSumMismatch); + /// Verify all the output rangeproofs. + /// Note: this is expensive. + fn verify_rangeproofs(&self) -> Result<(), Error> { + for x in &self.outputs { + x.verify_proof()?; } - - Ok((io_sum, kernel_sum)) + Ok(()) } /// Validate the coinbase outputs generated by miners. Entails 2 main diff --git a/core/src/core/committed.rs b/core/src/core/committed.rs new file mode 100644 index 000000000..7f8d7b8a3 --- /dev/null +++ b/core/src/core/committed.rs @@ -0,0 +1,169 @@ +// 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. + +//! The Committed trait and associated errors. + +use keychain; +use keychain::BlindingFactor; + +use util::secp::pedersen::*; +use util::{secp, secp_static, static_secp_instance}; + +/// Errors from summing and verifying kernel excesses via committed trait. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Error { + /// Keychain related error. + Keychain(keychain::Error), + /// Secp related error. + Secp(secp::Error), + /// Kernel sums do not equal output sums. + KernelSumMismatch, +} + +impl From for Error { + fn from(e: secp::Error) -> Error { + Error::Secp(e) + } +} + +impl From for Error { + fn from(e: keychain::Error) -> Error { + Error::Keychain(e) + } +} + +/// Implemented by types that hold inputs and outputs (and kernels) +/// containing Pedersen commitments. +/// Handles the collection of the commitments as well as their +/// summing, taking potential explicit overages of fees into account. +pub trait Committed { + /// Gather the kernel excesses and sum them. + fn sum_kernel_excesses( + &self, + offset: &BlindingFactor, + extra_excess: Option<&Commitment>, + ) -> Result<(Commitment, Commitment), Error> { + let zero_commit = secp_static::commit_to_zero_value(); + + // then gather the kernel excess commitments + let mut kernel_commits = self.kernels_committed(); + + if let Some(extra) = extra_excess { + kernel_commits.push(*extra); + } + + // handle "zero commit" values by filtering them out here + kernel_commits.retain(|x| *x != zero_commit); + + // sum the commitments + let kernel_sum = { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + secp.commit_sum(kernel_commits, vec![])? + }; + + // sum the commitments along with the + // commit to zero built from the offset + let kernel_sum_plus_offset = { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + let mut commits = vec![kernel_sum]; + if *offset != BlindingFactor::zero() { + let key = offset.secret_key(&secp)?; + let offset_commit = secp.commit(0, key)?; + commits.push(offset_commit); + } + secp.commit_sum(commits, vec![])? + }; + + Ok((kernel_sum, kernel_sum_plus_offset)) + } + + /// Gathers commitments and sum them. + fn sum_commitments( + &self, + overage: i64, + extra_commit: Option<&Commitment>, + ) -> Result { + let zero_commit = secp_static::commit_to_zero_value(); + + // then gather the commitments + let mut input_commits = self.inputs_committed(); + let mut output_commits = self.outputs_committed(); + + // add the overage as output commitment if positive, + // or as an input commitment if negative + if overage != 0 { + let over_commit = { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + secp.commit_value(overage.abs() as u64).unwrap() + }; + if overage < 0 { + input_commits.push(over_commit); + } else { + output_commits.push(over_commit); + } + } + + if let Some(extra) = extra_commit { + output_commits.push(*extra); + } + + // handle "zero commit" values by filtering them out here + output_commits.retain(|x| *x != zero_commit); + input_commits.retain(|x| *x != zero_commit); + + // sum all that stuff + { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + let res = secp.commit_sum(output_commits, input_commits)?; + Ok(res) + } + } + + /// Vector of input commitments to verify. + fn inputs_committed(&self) -> Vec; + + /// Vector of output commitments to verify. + fn outputs_committed(&self) -> Vec; + + /// Vector of kernel excesses to verify. + fn kernels_committed(&self) -> Vec; + + /// Verify the sum of the kernel excesses equals the + /// sum of the outputs, taking into account both + /// the kernel_offset and overage. + fn verify_kernel_sums( + &self, + overage: i64, + kernel_offset: BlindingFactor, + prev_output_sum: Option<&Commitment>, + prev_kernel_sum: Option<&Commitment>, + ) -> Result<((Commitment, Commitment)), Error> { + // Sum all input|output|overage commitments. + let utxo_sum = self.sum_commitments(overage, prev_output_sum)?; + + // Sum the kernel excesses accounting for the kernel offset. + let (kernel_sum, kernel_sum_plus_offset) = + self.sum_kernel_excesses(&kernel_offset, prev_kernel_sum)?; + + if utxo_sum != kernel_sum_plus_offset { + return Err(Error::KernelSumMismatch); + } + + Ok((utxo_sum, kernel_sum)) + } +} diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 3ab45245c..02adb2a87 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -15,6 +15,7 @@ //! Core types pub mod block; +pub mod committed; pub mod hash; pub mod id; pub mod pmmr; @@ -23,122 +24,19 @@ pub mod transaction; use consensus::GRIN_BASE; #[allow(dead_code)] use rand::{thread_rng, Rng}; -use std::cmp::Ordering; use std::num::ParseFloatError; use std::{fmt, iter}; use util::secp::pedersen::*; -use util::{secp, secp_static, static_secp_instance}; pub use self::block::*; +pub use self::committed::Committed; pub use self::id::ShortId; pub use self::transaction::*; use core::hash::Hashed; use global; -use keychain; -use keychain::BlindingFactor; use ser::{Error, Readable, Reader, Writeable, Writer}; -/// Implemented by types that hold inputs and outputs (and kernels) -/// containing Pedersen commitments. -/// Handles the collection of the commitments as well as their -/// summing, taking potential explicit overages of fees into account. -pub trait Committed { - /// Gather the kernel excesses and sum them. - fn sum_kernel_excesses( - &self, - offset: &BlindingFactor, - extra_excess: Option<&Commitment>, - ) -> Result<(Commitment, Commitment), keychain::Error> { - let zero_commit = secp_static::commit_to_zero_value(); - - // then gather the kernel excess commitments - let mut kernel_commits = self.kernels_committed(); - - if let Some(extra) = extra_excess { - kernel_commits.push(*extra); - } - - // handle "zero commit" values by filtering them out here - kernel_commits.retain(|x| *x != zero_commit); - - // sum the commitments - let kernel_sum = { - let secp = static_secp_instance(); - let secp = secp.lock().unwrap(); - secp.commit_sum(kernel_commits, vec![])? - }; - - // sum the commitments along with the - // commit to zero built from the offset - let kernel_sum_plus_offset = { - let secp = static_secp_instance(); - let secp = secp.lock().unwrap(); - let mut commits = vec![kernel_sum]; - if *offset != BlindingFactor::zero() { - let key = offset.secret_key(&secp)?; - let offset_commit = secp.commit(0, key)?; - commits.push(offset_commit); - } - secp.commit_sum(commits, vec![])? - }; - - Ok((kernel_sum, kernel_sum_plus_offset)) - } - - /// Gathers commitments and sum them. - fn sum_commitments( - &self, - overage: i64, - extra_commit: Option<&Commitment>, - ) -> Result { - let zero_commit = secp_static::commit_to_zero_value(); - - // then gather the commitments - let mut input_commits = self.inputs_committed(); - let mut output_commits = self.outputs_committed(); - - // add the overage as output commitment if positive, - // or as an input commitment if negative - if overage != 0 { - let over_commit = { - let secp = static_secp_instance(); - let secp = secp.lock().unwrap(); - secp.commit_value(overage.abs() as u64).unwrap() - }; - if overage < 0 { - input_commits.push(over_commit); - } else { - output_commits.push(over_commit); - } - } - - if let Some(extra) = extra_commit { - output_commits.push(*extra); - } - - // handle "zero commit" values by filtering them out here - output_commits.retain(|x| *x != zero_commit); - input_commits.retain(|x| *x != zero_commit); - - // sum all that stuff - { - let secp = static_secp_instance(); - let secp = secp.lock().unwrap(); - secp.commit_sum(output_commits, input_commits) - } - } - - /// Vector of input commitments to verify. - fn inputs_committed(&self) -> Vec; - - /// Vector of output commitments to verify. - fn outputs_committed(&self) -> Vec; - - /// Vector of kernel excesses to verify. - fn kernels_committed(&self) -> Vec; -} - /// Proof of work #[derive(Clone, PartialOrd, PartialEq)] pub struct Proof { diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index e25a9ce6e..f2b25ede2 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -14,8 +14,8 @@ //! Transactions -use std::cmp::Ordering; use std::cmp::max; +use std::cmp::Ordering; use std::collections::HashSet; use std::io::Cursor; use std::{error, fmt}; @@ -26,11 +26,12 @@ use util::{kernel_sig_msg, static_secp_instance}; use consensus; use consensus::VerifySortOrder; -use core::BlockHeader; -use core::Committed; +use core::committed; +use core::committed::Committed; use core::global; use core::hash::{Hash, Hashed, ZERO_HASH}; use core::pmmr::MerkleProof; +use core::BlockHeader; use keychain; use keychain::BlindingFactor; use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable, @@ -75,9 +76,8 @@ pub enum Error { /// Returns if the value hidden within the a RangeProof message isn't /// repeated 3 times, indicating it's incorrect InvalidProofMessage, - /// Error when sums do not verify correctly during tx aggregation. - /// Likely a "double spend" across two unconfirmed txs. - AggregationError, + /// Error when verifying kernel sums via committed trait. + Committed(committed::Error), } impl error::Error for Error { @@ -114,6 +114,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: committed::Error) -> Error { + Error::Committed(e) + } +} + /// A proof that a transaction sums to zero. Includes both the transaction's /// Pedersen commitment and the signature, that guarantees that the commitments /// amount to zero. @@ -387,6 +393,10 @@ impl Transaction { self.kernels.iter().fold(0, |acc, ref x| acc + x.fee) } + fn overage(&self) -> i64 { + self.fee() as i64 + } + /// Lock height of a transaction is the max lock height of the kernels. pub fn lock_height(&self) -> u64 { self.kernels @@ -394,46 +404,24 @@ impl Transaction { .fold(0, |acc, ref x| max(acc, x.lock_height)) } + /// Verify the kernel signatures. + /// Note: this is expensive. fn verify_kernel_signatures(&self) -> Result<(), Error> { - // Verify the kernel signatures. - // Note: this is expensive. for x in &self.kernels { x.verify()?; } Ok(()) } + /// Verify all the output rangeproofs. + /// Note: this is expensive. fn verify_rangeproofs(&self) -> Result<(), Error> { - // Verify all the output rangeproofs. - // Note: this is expensive. for x in &self.outputs { x.verify_proof()?; } Ok(()) } - /// To verify transaction kernels we check that - - /// * all kernels have an even fee - /// * sum of input/output commitments matches sum of kernel commitments - /// after applying offset * each kernel sig is valid (i.e. tx commitments - /// sum to zero, given above is true) - fn verify_kernel_sums(&self) -> Result<(), Error> { - // Sum all input|output|overage commitments. - let overage = self.fee() as i64; - let io_sum = self.sum_commitments(overage, None)?; - - // Sum the kernel excesses accounting for the kernel offset. - let (_, kernel_sum) = self.sum_kernel_excesses(&self.offset, None)?; - - // sum of kernel commitments (including the offset) must match - // the sum of input/output commitments (minus fee) - if io_sum != kernel_sum { - return Err(Error::KernelSumMismatch); - } - - Ok(()) - } - /// Validates all relevant parts of a fully built transaction. Checks the /// excess value against the signature as well as range proofs for each /// output. @@ -442,7 +430,7 @@ impl Transaction { return Err(Error::TooManyInputs); } self.verify_sorted()?; - self.verify_kernel_sums()?; + self.verify_kernel_sums(self.overage(), self.offset, None, None)?; self.verify_rangeproofs()?; self.verify_kernel_signatures()?; @@ -553,10 +541,9 @@ pub fn aggregate(transactions: Vec) -> Result { let tx = Transaction::new(new_inputs, new_outputs, kernels).with_offset(total_kernel_offset); - // We need to check sums here as aggregation/cut-through may have created an - // invalid tx. - tx.verify_kernel_sums() - .map_err(|_| Error::AggregationError)?; + // We need to check sums here as aggregation/cut-through + // may have created an invalid tx. + tx.verify_kernel_sums(tx.overage(), tx.offset, None, None)?; Ok(tx) } diff --git a/core/tests/block.rs b/core/tests/block.rs index f9bb8b96b..c1b8c2d4a 100644 --- a/core/tests/block.rs +++ b/core/tests/block.rs @@ -24,6 +24,7 @@ use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT}; use grin_core::core::block::Error; use grin_core::core::hash::Hashed; use grin_core::core::id::{ShortId, ShortIdentifiable}; +use grin_core::core::Committed; use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures}; use grin_core::global; use grin_core::ser; @@ -167,7 +168,12 @@ fn remove_coinbase_output_flag() { .remove(OutputFeatures::COINBASE_OUTPUT); assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch)); - assert!(b.verify_sums(&zero_commit, &zero_commit).is_ok()); + assert!(b.verify_kernel_sums( + b.header.overage(), + b.header.total_kernel_offset(), + None, + None + ).is_ok()); assert_eq!( b.validate(&zero_commit, &zero_commit), Err(Error::CoinbaseSumMismatch) diff --git a/wallet/src/libtx/error.rs b/wallet/src/libtx/error.rs index b2dd980d7..3772ddf2d 100644 --- a/wallet/src/libtx/error.rs +++ b/wallet/src/libtx/error.rs @@ -16,6 +16,7 @@ use failure::{Backtrace, Context, Fail}; use std::fmt::{self, Display}; +use core::core::committed; use core::core::transaction; use keychain::{self, extkey}; use util::secp; @@ -50,6 +51,9 @@ pub enum ErrorKind { /// Fee error #[fail(display = "Fee Error")] Fee(String), + /// Error from summing commitments via committed trait. + #[fail(display = "Committed Error")] + Committed(committed::Error), } impl Fail for Error { @@ -97,6 +101,14 @@ impl From for Error { } } +impl From for Error { + fn from(error: committed::Error) -> Error { + Error { + inner: Context::new(ErrorKind::Committed(error)), + } + } +} + impl From for Error { fn from(error: keychain::Error) -> Error { Error { diff --git a/wallet/src/libtx/slate.rs b/wallet/src/libtx/slate.rs index e2f57047e..69f6e3fe7 100644 --- a/wallet/src/libtx/slate.rs +++ b/wallet/src/libtx/slate.rs @@ -17,13 +17,15 @@ use rand::thread_rng; use uuid::Uuid; -use core::core::{amount_to_hr_string, Committed, Transaction}; +use core::core::committed; +use core::core::committed::Committed; +use core::core::{amount_to_hr_string, Transaction}; use keychain::{BlindSum, BlindingFactor, Keychain}; use libtx::error::{Error, ErrorKind}; use libtx::{aggsig, build, tx_fee}; -use util::secp::Signature; use util::secp::key::{PublicKey, SecretKey}; +use util::secp::Signature; use util::{secp, LOGGER}; /// Public data for each participant in the slate