Resolve merging crypto-{audit, tweaks} and use the proper transcript in Bitcoin

This commit is contained in:
Luke Parker
2023-03-16 16:59:20 -04:00
parent 64924835ad
commit d2c1592c61
8 changed files with 75 additions and 36 deletions

43
Cargo.lock generated
View File

@@ -602,7 +602,7 @@ dependencies = [
"bitcoin", "bitcoin",
"flexible-transcript", "flexible-transcript",
"hex", "hex",
"k256", "k256 0.12.0",
"lazy_static", "lazy_static",
"modular-frost", "modular-frost",
"rand_core 0.6.4", "rand_core 0.6.4",
@@ -1037,7 +1037,7 @@ dependencies = [
"hex", "hex",
"k256 0.12.0", "k256 0.12.0",
"minimal-ed448", "minimal-ed448",
"p256", "p256 0.12.0",
"rand_core 0.6.4", "rand_core 0.6.4",
"sha2 0.10.6", "sha2 0.10.6",
"sha3", "sha3",
@@ -2599,7 +2599,7 @@ version = "0.12.0"
dependencies = [ dependencies = [
"group", "group",
"k256 0.12.0", "k256 0.12.0",
"p256", "p256 0.12.0",
"rand_core 0.6.4", "rand_core 0.6.4",
] ]
@@ -3350,6 +3350,15 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
[[package]]
name = "hkdf"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
dependencies = [
"hmac 0.12.1",
]
[[package]] [[package]]
name = "hmac" name = "hmac"
version = "0.8.1" version = "0.8.1"
@@ -5575,6 +5584,17 @@ version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "p256"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
dependencies = [
"ecdsa 0.14.8",
"elliptic-curve",
"sha2 0.10.6",
]
[[package]] [[package]]
name = "p256" name = "p256"
version = "0.12.0" version = "0.12.0"
@@ -5587,6 +5607,17 @@ dependencies = [
"sha2 0.10.6", "sha2 0.10.6",
] ]
[[package]]
name = "p384"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
dependencies = [
"ecdsa 0.14.8",
"elliptic-curve",
"sha2 0.10.6",
]
[[package]] [[package]]
name = "packed_simd_2" name = "packed_simd_2"
version = "0.3.8" version = "0.3.8"
@@ -8224,7 +8255,7 @@ dependencies = [
"futures", "futures",
"group", "group",
"hex", "hex",
"k256", "k256 0.12.0",
"modular-frost", "modular-frost",
"monero-serai", "monero-serai",
"rand_core 0.6.4", "rand_core 0.6.4",
@@ -10788,7 +10819,7 @@ dependencies = [
"hmac 0.12.1", "hmac 0.12.1",
"log", "log",
"oid-registry 0.6.1", "oid-registry 0.6.1",
"p256", "p256 0.11.1",
"p384", "p384",
"rand 0.8.5", "rand 0.8.5",
"rand_core 0.6.4", "rand_core 0.6.4",
@@ -10799,7 +10830,7 @@ dependencies = [
"serde", "serde",
"sha1", "sha1",
"sha2 0.10.6", "sha2 0.10.6",
"signature", "signature 1.6.4",
"subtle", "subtle",
"thiserror", "thiserror",
"tokio", "tokio",

View File

@@ -18,7 +18,7 @@ sha2 = "0.10"
secp256k1 = { version = "0.24", features = ["global-context"] } secp256k1 = { version = "0.24", features = ["global-context"] }
bitcoin = { version = "0.29", features = ["serde"] } bitcoin = { version = "0.29", features = ["serde"] }
k256 = { version = "0.11", features = ["arithmetic"] } k256 = { version = "0.12", features = ["arithmetic"] }
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.2", features = ["recommended"] } transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.2", features = ["recommended"] }
frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["secp256k1"] } frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["secp256k1"] }

View File

@@ -8,7 +8,8 @@ use bitcoin::hashes::{Hash as HashTrait, sha256::Hash};
use k256::Scalar; use k256::Scalar;
use frost::{ use frost::{
curve::Secp256k1, curve::Secp256k1,
algorithm::Schnorr, Participant,
algorithm::IetfSchnorr,
tests::{algorithm_machines, key_gen, sign}, tests::{algorithm_machines, key_gen, sign},
}; };
@@ -24,12 +25,12 @@ fn test_signing() {
*keys = keys.offset(Scalar::from(offset)); *keys = keys.offset(Scalar::from(offset));
} }
let algo = Schnorr::<Secp256k1, BitcoinHram>::new(); let algo = IetfSchnorr::<Secp256k1, BitcoinHram>::ietf();
let mut sig = sign( let mut sig = sign(
&mut OsRng, &mut OsRng,
algo, algo,
keys.clone(), keys.clone(),
algorithm_machines(&mut OsRng, Schnorr::<Secp256k1, BitcoinHram>::new(), &keys), algorithm_machines(&mut OsRng, IetfSchnorr::ietf(), &keys),
&Sha256::digest(MESSAGE), &Sha256::digest(MESSAGE),
); );
@@ -41,7 +42,7 @@ fn test_signing() {
.verify_schnorr( .verify_schnorr(
&Signature::from_slice(&sig.serialize()[1 .. 65]).unwrap(), &Signature::from_slice(&sig.serialize()[1 .. 65]).unwrap(),
&Message::from(Hash::hash(MESSAGE)), &Message::from(Hash::hash(MESSAGE)),
&x_only(&keys[&1].group_key()), &x_only(&keys[&Participant::new(1).unwrap()].group_key()),
) )
.unwrap() .unwrap()
} }

View File

@@ -10,7 +10,7 @@ use transcript::{Transcript, RecommendedTranscript};
use k256::{elliptic_curve::sec1::ToEncodedPoint, Scalar}; use k256::{elliptic_curve::sec1::ToEncodedPoint, Scalar};
use frost::{ use frost::{
curve::{Ciphersuite, Secp256k1}, curve::{Ciphersuite, Secp256k1},
ThresholdKeys, FrostError, Participant, ThresholdKeys, FrostError,
algorithm::Schnorr, algorithm::Schnorr,
sign::*, sign::*,
}; };
@@ -168,25 +168,21 @@ impl SignableTransaction {
let mut sigs = vec![]; let mut sigs = vec![];
for i in 0 .. tx.input.len() { for i in 0 .. tx.input.len() {
// TODO: Use the above transcript here let mut transcript = transcript.clone();
transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes());
sigs.push( sigs.push(
AlgorithmMachine::new( AlgorithmMachine::new(Schnorr::new(transcript), keys.clone().offset(self.1[i])).unwrap(),
Schnorr::<Secp256k1, BitcoinHram>::new(),
keys.clone().offset(self.1[i]),
)
.unwrap(),
); );
} }
Ok(TransactionMachine { tx: self, transcript, sigs }) Ok(TransactionMachine { tx: self, sigs })
} }
} }
/// A FROST signing machine to produce a Bitcoin transaction. /// A FROST signing machine to produce a Bitcoin transaction.
pub struct TransactionMachine { pub struct TransactionMachine {
tx: SignableTransaction, tx: SignableTransaction,
transcript: RecommendedTranscript, sigs: Vec<AlgorithmMachine<Secp256k1, Schnorr<Secp256k1, RecommendedTranscript, BitcoinHram>>>,
sigs: Vec<AlgorithmMachine<Secp256k1, Schnorr<Secp256k1, BitcoinHram>>>,
} }
impl PreprocessMachine for TransactionMachine { impl PreprocessMachine for TransactionMachine {
@@ -209,14 +205,14 @@ impl PreprocessMachine for TransactionMachine {
}) })
.collect(); .collect();
(TransactionSignMachine { tx: self.tx, transcript: self.transcript, sigs }, preprocesses) (TransactionSignMachine { tx: self.tx, sigs }, preprocesses)
} }
} }
pub struct TransactionSignMachine { pub struct TransactionSignMachine {
tx: SignableTransaction, tx: SignableTransaction,
transcript: RecommendedTranscript, sigs:
sigs: Vec<AlgorithmSignMachine<Secp256k1, Schnorr<Secp256k1, BitcoinHram>>>, Vec<AlgorithmSignMachine<Secp256k1, Schnorr<Secp256k1, RecommendedTranscript, BitcoinHram>>>,
} }
impl SignMachine<Transaction> for TransactionSignMachine { impl SignMachine<Transaction> for TransactionSignMachine {
@@ -250,7 +246,7 @@ impl SignMachine<Transaction> for TransactionSignMachine {
fn sign( fn sign(
mut self, mut self,
commitments: HashMap<u16, Self::Preprocess>, commitments: HashMap<Participant, Self::Preprocess>,
msg: &[u8], msg: &[u8],
) -> Result<(TransactionSignatureMachine, Self::SignatureShare), FrostError> { ) -> Result<(TransactionSignatureMachine, Self::SignatureShare), FrostError> {
if !msg.is_empty() { if !msg.is_empty() {
@@ -293,7 +289,9 @@ impl SignMachine<Transaction> for TransactionSignMachine {
pub struct TransactionSignatureMachine { pub struct TransactionSignatureMachine {
tx: Transaction, tx: Transaction,
sigs: Vec<AlgorithmSignatureMachine<Secp256k1, Schnorr<Secp256k1, BitcoinHram>>>, sigs: Vec<
AlgorithmSignatureMachine<Secp256k1, Schnorr<Secp256k1, RecommendedTranscript, BitcoinHram>>,
>,
} }
impl SignatureMachine<Transaction> for TransactionSignatureMachine { impl SignatureMachine<Transaction> for TransactionSignatureMachine {
@@ -305,7 +303,7 @@ impl SignatureMachine<Transaction> for TransactionSignatureMachine {
fn complete( fn complete(
mut self, mut self,
mut shares: HashMap<u16, Self::SignatureShare>, mut shares: HashMap<Participant, Self::SignatureShare>,
) -> Result<Transaction, FrostError> { ) -> Result<Transaction, FrostError> {
for (input, schnorr) in self.tx.input.iter_mut().zip(self.sigs.drain(..)) { for (input, schnorr) in self.tx.input.iter_mut().zip(self.sigs.drain(..)) {
let mut sig = schnorr.complete( let mut sig = schnorr.complete(

View File

@@ -12,9 +12,10 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[dependencies] [dependencies]
futures = "0.3"
lazy_static = "1" lazy_static = "1"
thiserror = "1" thiserror = "1"
crc = "3"
rand_core = "0.6" rand_core = "0.6"
rand_chacha = { version = "0.3", optional = true } rand_chacha = { version = "0.3", optional = true }
@@ -24,6 +25,7 @@ rand_distr = "0.4"
zeroize = { version = "^1.5", features = ["zeroize_derive"] } zeroize = { version = "^1.5", features = ["zeroize_derive"] }
subtle = "^2.4" subtle = "^2.4"
crc = "3"
sha3 = "0.10" sha3 = "0.10"
curve25519-dalek = { version = "^3.2", features = ["std"] } curve25519-dalek = { version = "^3.2", features = ["std"] }

View File

@@ -184,7 +184,7 @@ fn core(
let L = (&s[i] * &ED25519_BASEPOINT_TABLE) + (c_p * P[i]) + (c_c * C[i]); let L = (&s[i] * &ED25519_BASEPOINT_TABLE) + (c_p * P[i]) + (c_c * C[i]);
let PH = hash_to_point(P[i]); let PH = hash_to_point(P[i]);
// Shouldn't be an issue as all of the variables in this vartime statement are public // Shouldn't be an issue as all of the variables in this vartime statement are public
let R = (s[i] * PH) + images_precomp.vartime_multiscalar_mul(&[c_p, c_c]); let R = (s[i] * PH) + images_precomp.vartime_multiscalar_mul([c_p, c_c]);
to_hash.truncate(((2 * n) + 3) * 32); to_hash.truncate(((2 * n) + 3) * 32);
to_hash.extend(L.compress().to_bytes()); to_hash.extend(L.compress().to_bytes());

View File

@@ -7,6 +7,8 @@ use async_trait::async_trait;
use rand_core::OsRng; use rand_core::OsRng;
use frost::Participant;
use crate::{ use crate::{
NetworkError, Network, NetworkError, Network,
coin::Coin, coin::Coin,
@@ -15,11 +17,11 @@ use crate::{
#[derive(Clone)] #[derive(Clone)]
struct LocalNetwork { struct LocalNetwork {
i: u16, i: Participant,
size: u16, size: u16,
round: usize, round: usize,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
rounds: Arc<RwLock<Vec<HashMap<u16, Vec<u8>>>>>, rounds: Arc<RwLock<Vec<HashMap<Participant, Vec<u8>>>>>,
} }
impl LocalNetwork { impl LocalNetwork {
@@ -27,7 +29,12 @@ impl LocalNetwork {
let rounds = Arc::new(RwLock::new(vec![])); let rounds = Arc::new(RwLock::new(vec![]));
let mut res = vec![]; let mut res = vec![];
for i in 1 ..= size { for i in 1 ..= size {
res.push(LocalNetwork { i, size, round: 0, rounds: rounds.clone() }); res.push(LocalNetwork {
i: Participant::new(i).unwrap(),
size,
round: 0,
rounds: rounds.clone(),
});
} }
res res
} }
@@ -35,7 +42,7 @@ impl LocalNetwork {
#[async_trait] #[async_trait]
impl Network for LocalNetwork { impl Network for LocalNetwork {
async fn round(&mut self, data: Vec<u8>) -> Result<HashMap<u16, Vec<u8>>, NetworkError> { async fn round(&mut self, data: Vec<u8>) -> Result<HashMap<Participant, Vec<u8>>, NetworkError> {
{ {
let mut rounds = self.rounds.write().unwrap(); let mut rounds = self.rounds.write().unwrap();
if rounds.len() == self.round { if rounds.len() == self.round {
@@ -64,14 +71,14 @@ pub async fn test_send<C: Coin + Clone>(coin: C, fee: C::Fee) {
let latest = coin.get_latest_block_number().await.unwrap(); let latest = coin.get_latest_block_number().await.unwrap();
let mut keys = frost::tests::key_gen::<_, C::Curve>(&mut OsRng); let mut keys = frost::tests::key_gen::<_, C::Curve>(&mut OsRng);
let threshold = keys[&1].params().t(); let threshold = keys[&Participant::new(1).unwrap()].params().t();
let mut networks = LocalNetwork::new(threshold); let mut networks = LocalNetwork::new(threshold);
let mut wallets = vec![]; let mut wallets = vec![];
for i in 1 ..= threshold { for i in 1 ..= threshold {
let mut wallet = Wallet::new(MemCoinDb::new(), coin.clone()); let mut wallet = Wallet::new(MemCoinDb::new(), coin.clone());
wallet.acknowledge_block(0, latest); wallet.acknowledge_block(0, latest);
wallet.add_keys(&WalletKeys::new(keys.remove(&i).unwrap(), 0)); wallet.add_keys(&WalletKeys::new(keys.remove(&Participant::new(i).unwrap()).unwrap(), 0));
wallets.push(wallet); wallets.push(wallet);
} }