From 3af430d8de720ae51b227a6280c6891f21b13f0f Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Thu, 19 Sep 2024 21:13:08 -0400 Subject: [PATCH] Use the IETF transacript in bitcoin-serai, not RecommendedTranscript This is more likely to be interoperable in the long term. --- Cargo.lock | 1 - networks/bitcoin/Cargo.toml | 6 +--- networks/bitcoin/src/crypto.rs | 17 ++++++----- networks/bitcoin/src/tests/crypto.rs | 4 +-- networks/bitcoin/src/wallet/send.rs | 42 +++++----------------------- networks/bitcoin/tests/wallet.rs | 9 +----- processor/src/networks/bitcoin.rs | 18 ++---------- 7 files changed, 21 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aeab97f3..d743f1df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1054,7 +1054,6 @@ name = "bitcoin-serai" version = "0.3.0" dependencies = [ "bitcoin", - "flexible-transcript", "hex", "k256", "modular-frost", diff --git a/networks/bitcoin/Cargo.toml b/networks/bitcoin/Cargo.toml index 03d7f543..5ab44cc6 100644 --- a/networks/bitcoin/Cargo.toml +++ b/networks/bitcoin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin-serai" -version = "0.4.0" +version = "0.3.0" description = "A Bitcoin library for FROST-signing transactions" license = "MIT" repository = "https://github.com/serai-dex/serai/tree/develop/networks/bitcoin" @@ -26,8 +26,6 @@ rand_core = { version = "0.6", default-features = false } bitcoin = { version = "0.32", default-features = false } k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] } - -transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true } frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", default-features = false, features = ["secp256k1"], optional = true } hex = { version = "0.4", default-features = false, optional = true } @@ -55,8 +53,6 @@ std = [ "bitcoin/serde", "k256/std", - - "transcript/std", "frost", "hex/std", diff --git a/networks/bitcoin/src/crypto.rs b/networks/bitcoin/src/crypto.rs index 72aff20c..11510909 100644 --- a/networks/bitcoin/src/crypto.rs +++ b/networks/bitcoin/src/crypto.rs @@ -40,14 +40,12 @@ mod frost_crypto { use bitcoin::hashes::{HashEngine, Hash, sha256::Hash as Sha256}; - use transcript::Transcript; - use k256::{elliptic_curve::ops::Reduce, U256, Scalar}; use frost::{ curve::{Ciphersuite, Secp256k1}, Participant, ThresholdKeys, ThresholdView, FrostError, - algorithm::{Hram as HramTrait, Algorithm, Schnorr as FrostSchnorr}, + algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr}, }; use super::*; @@ -82,16 +80,17 @@ mod frost_crypto { /// /// This must be used with a ThresholdKeys whose group key is even. If it is odd, this will panic. #[derive(Clone)] - pub struct Schnorr(FrostSchnorr); - impl Schnorr { + pub struct Schnorr(FrostSchnorr); + impl Schnorr { /// Construct a Schnorr algorithm continuing the specified transcript. - pub fn new(transcript: T) -> Schnorr { - Schnorr(FrostSchnorr::new(transcript)) + #[allow(clippy::new_without_default)] + pub fn new() -> Schnorr { + Schnorr(FrostSchnorr::ietf()) } } - impl Algorithm for Schnorr { - type Transcript = T; + impl Algorithm for Schnorr { + type Transcript = as Algorithm>::Transcript; type Addendum = (); type Signature = [u8; 64]; diff --git a/networks/bitcoin/src/tests/crypto.rs b/networks/bitcoin/src/tests/crypto.rs index cfc694f4..57a0eb3e 100644 --- a/networks/bitcoin/src/tests/crypto.rs +++ b/networks/bitcoin/src/tests/crypto.rs @@ -3,7 +3,6 @@ use rand_core::OsRng; use secp256k1::{Secp256k1 as BContext, Message, schnorr::Signature}; use k256::Scalar; -use transcript::{Transcript, RecommendedTranscript}; use frost::{ curve::Secp256k1, Participant, @@ -25,8 +24,7 @@ fn test_algorithm() { *keys = keys.offset(Scalar::from(offset)); } - let algo = - Schnorr::::new(RecommendedTranscript::new(b"bitcoin-serai sign test")); + let algo = Schnorr::new(); let sig = sign( &mut OsRng, &algo, diff --git a/networks/bitcoin/src/wallet/send.rs b/networks/bitcoin/src/wallet/send.rs index 9a723523..ccb020b2 100644 --- a/networks/bitcoin/src/wallet/send.rs +++ b/networks/bitcoin/src/wallet/send.rs @@ -7,9 +7,7 @@ use thiserror::Error; use rand_core::{RngCore, CryptoRng}; -use transcript::{Transcript, RecommendedTranscript}; - -use k256::{elliptic_curve::sec1::ToEncodedPoint, Scalar}; +use k256::Scalar; use frost::{curve::Secp256k1, Participant, ThresholdKeys, FrostError, sign::*}; use bitcoin::{ @@ -268,41 +266,15 @@ impl SignableTransaction { /// Create a multisig machine for this transaction. /// /// Returns None if the wrong keys are used. - pub fn multisig( - self, - keys: &ThresholdKeys, - mut transcript: RecommendedTranscript, - ) -> Option { - transcript.domain_separate(b"bitcoin_transaction"); - transcript.append_message(b"root_key", keys.group_key().to_encoded_point(true).as_bytes()); - - // Transcript the inputs and outputs - let tx = &self.tx; - for input in &tx.input { - transcript.append_message(b"input_hash", input.previous_output.txid); - transcript.append_message(b"input_output_index", input.previous_output.vout.to_le_bytes()); - } - for payment in &tx.output { - transcript.append_message(b"output_script", payment.script_pubkey.as_bytes()); - transcript.append_message(b"output_amount", payment.value.to_sat().to_le_bytes()); - } - + pub fn multisig(self, keys: &ThresholdKeys) -> Option { let mut sigs = vec![]; - for i in 0 .. tx.input.len() { - let mut transcript = transcript.clone(); - // This unwrap is safe since any transaction with this many inputs violates the maximum - // size allowed under standards, which this lib will error on creation of - transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes()); - + for i in 0 .. self.tx.input.len() { let offset = keys.clone().offset(self.offsets[i]); if p2tr_script_buf(offset.group_key())? != self.prevouts[i].script_pubkey { None?; } - sigs.push(AlgorithmMachine::new( - Schnorr::new(transcript), - keys.clone().offset(self.offsets[i]), - )); + sigs.push(AlgorithmMachine::new(Schnorr::new(), keys.clone().offset(self.offsets[i]))); } Some(TransactionMachine { tx: self, sigs }) @@ -315,7 +287,7 @@ impl SignableTransaction { /// This will panic if either `cache` is called or the message isn't empty. pub struct TransactionMachine { tx: SignableTransaction, - sigs: Vec>>, + sigs: Vec>, } impl PreprocessMachine for TransactionMachine { @@ -344,7 +316,7 @@ impl PreprocessMachine for TransactionMachine { pub struct TransactionSignMachine { tx: SignableTransaction, - sigs: Vec>>, + sigs: Vec>, } impl SignMachine for TransactionSignMachine { @@ -424,7 +396,7 @@ impl SignMachine for TransactionSignMachine { pub struct TransactionSignatureMachine { tx: Transaction, - sigs: Vec>>, + sigs: Vec>, } impl SignatureMachine for TransactionSignatureMachine { diff --git a/networks/bitcoin/tests/wallet.rs b/networks/bitcoin/tests/wallet.rs index 4b77e61a..e5ce1cff 100644 --- a/networks/bitcoin/tests/wallet.rs +++ b/networks/bitcoin/tests/wallet.rs @@ -2,8 +2,6 @@ use std::collections::HashMap; use rand_core::{RngCore, OsRng}; -use transcript::{Transcript, RecommendedTranscript}; - use k256::{ elliptic_curve::{ group::{ff::Field, Group}, @@ -94,12 +92,7 @@ fn sign( ) -> Transaction { let mut machines = HashMap::new(); for i in (1 ..= THRESHOLD).map(|i| Participant::new(i).unwrap()) { - machines.insert( - i, - tx.clone() - .multisig(&keys[&i].clone(), RecommendedTranscript::new(b"bitcoin-serai Test Transaction")) - .unwrap(), - ); + machines.insert(i, tx.clone().multisig(&keys[&i].clone()).unwrap()); } sign_without_caching(&mut OsRng, machines, &[]) } diff --git a/processor/src/networks/bitcoin.rs b/processor/src/networks/bitcoin.rs index ae62f4c8..43cad1c7 100644 --- a/processor/src/networks/bitcoin.rs +++ b/processor/src/networks/bitcoin.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use scale::{Encode, Decode}; -use transcript::{Transcript, RecommendedTranscript}; use ciphersuite::group::ff::PrimeField; use k256::{ProjectivePoint, Scalar}; use frost::{ @@ -249,7 +248,6 @@ impl EventualityTrait for Eventuality { #[derive(Clone, Debug)] pub struct SignableTransaction { - transcript: RecommendedTranscript, actual: BSignableTransaction, } impl PartialEq for SignableTransaction { @@ -820,7 +818,7 @@ impl Network for Bitcoin { async fn signable_transaction( &self, block_number: usize, - plan_id: &[u8; 32], + _plan_id: &[u8; 32], _key: ProjectivePoint, inputs: &[Output], payments: &[Payment], @@ -829,12 +827,8 @@ impl Network for Bitcoin { ) -> Result, NetworkError> { Ok(self.make_signable_transaction(block_number, inputs, payments, change, false).await?.map( |signable| { - let mut transcript = - RecommendedTranscript::new(b"Serai Processor Bitcoin Transaction Transcript"); - transcript.append_message(b"plan", plan_id); - let eventuality = Eventuality(signable.txid()); - (SignableTransaction { transcript, actual: signable }, eventuality) + (SignableTransaction { actual: signable }, eventuality) }, )) } @@ -844,13 +838,7 @@ impl Network for Bitcoin { keys: ThresholdKeys, transaction: Self::SignableTransaction, ) -> Result { - Ok( - transaction - .actual - .clone() - .multisig(&keys, transaction.transcript) - .expect("used the wrong keys"), - ) + Ok(transaction.actual.clone().multisig(&keys).expect("used the wrong keys")) } async fn publish_completion(&self, tx: &Transaction) -> Result<(), NetworkError> {