From df75782e54892e99672d8778a38a1aebcb51d71c Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 31 Jan 2023 09:28:03 -0500 Subject: [PATCH] Re-license bitcoin-serai to MIT It's pretty basic code, yet would still be quite pleasant to the larger community. Also adds documentation. --- coins/bitcoin/Cargo.toml | 8 +++++--- coins/bitcoin/LICENSE | 26 ++++++++++++++++---------- coins/bitcoin/src/crypto.rs | 7 +++++-- coins/bitcoin/src/lib.rs | 3 +++ coins/bitcoin/src/wallet.rs | 28 +++++++++++++++++++++++----- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/coins/bitcoin/Cargo.toml b/coins/bitcoin/Cargo.toml index de987bbc..e9d33c72 100644 --- a/coins/bitcoin/Cargo.toml +++ b/coins/bitcoin/Cargo.toml @@ -2,11 +2,10 @@ name = "bitcoin-serai" version = "0.1.0" description = "A Bitcoin library for FROST-signing transactions" -license = "AGPL-3.0-only" +license = "MIT" repository = "https://github.com/serai-dex/serai/tree/develop/coins/bitcoin" authors = ["Luke Parker ", "Vrx "] edition = "2021" -publish = false [dependencies] lazy_static = "1" @@ -21,9 +20,12 @@ bitcoin = { version = "0.29", features = ["serde"] } k256 = { version = "0.11", features = ["arithmetic"] } transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.2", features = ["recommended"] } -frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["secp256k1", "tests"] } +frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["secp256k1"] } hex = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" reqwest = { version = "0.11", features = ["json"] } + +[dev-dependencies] +frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["tests"] } diff --git a/coins/bitcoin/LICENSE b/coins/bitcoin/LICENSE index c425427c..6779f0ec 100644 --- a/coins/bitcoin/LICENSE +++ b/coins/bitcoin/LICENSE @@ -1,15 +1,21 @@ -AGPL-3.0-only license +MIT License Copyright (c) 2022-2023 Luke Parker -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License Version 3 as -published by the Free Software Foundation. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/coins/bitcoin/src/crypto.rs b/coins/bitcoin/src/crypto.rs index bea62831..73e2077d 100644 --- a/coins/bitcoin/src/crypto.rs +++ b/coins/bitcoin/src/crypto.rs @@ -14,17 +14,19 @@ use bitcoin::XOnlyPublicKey; use frost::{algorithm::Hram, curve::Secp256k1}; -/// Get the x coordinate of a non-infinity, even point. +/// Get the x coordinate of a non-infinity, even point. Panics on invalid input. pub fn x(key: &ProjectivePoint) -> [u8; 32] { let encoded = key.to_encoded_point(true); assert_eq!(encoded.tag(), Tag::CompressedEvenY); (*encoded.x().expect("point at infinity")).into() } +/// Convert a non-infinite even point to a XOnlyPublicKey. Panics on invalid input. pub fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey { XOnlyPublicKey::from_slice(&x(key)).unwrap() } +/// Make a point even, returning the even version and the offset required for it to be even. pub fn make_even(mut key: ProjectivePoint) -> (ProjectivePoint, u64) { let mut c = 0; while key.to_encoded_point(true).tag() == Tag::CompressedOddY { @@ -34,7 +36,8 @@ pub fn make_even(mut key: ProjectivePoint) -> (ProjectivePoint, u64) { (key, c) } -#[derive(Clone)] +/// A BIP-340 compatible HRAm for use with the modular-frost Schnorr Algorithm. +#[derive(Clone, Copy, Debug)] pub struct BitcoinHram {} lazy_static! { diff --git a/coins/bitcoin/src/lib.rs b/coins/bitcoin/src/lib.rs index 22c1c26c..cdd28b9c 100644 --- a/coins/bitcoin/src/lib.rs +++ b/coins/bitcoin/src/lib.rs @@ -1,5 +1,8 @@ +/// Cryptographic helpers. pub mod crypto; +/// Wallet functionality to create transactions. pub mod wallet; +/// A minimal async RPC. pub mod rpc; #[cfg(test)] diff --git a/coins/bitcoin/src/wallet.rs b/coins/bitcoin/src/wallet.rs index e641e7c1..d5905db9 100644 --- a/coins/bitcoin/src/wallet.rs +++ b/coins/bitcoin/src/wallet.rs @@ -1,5 +1,5 @@ use std::{ - io::{self, Read}, + io::{self, Read, Write}, collections::HashMap, }; @@ -17,25 +17,32 @@ use frost::{ use bitcoin::{ hashes::Hash, - consensus::encode::{Encodable, Decodable, serialize}, + consensus::encode::{Decodable, serialize}, util::sighash::{SchnorrSighashType, SighashCache, Prevouts}, OutPoint, Script, Sequence, Witness, TxIn, TxOut, PackedLockTime, Transaction, Address, }; use crate::crypto::{BitcoinHram, make_even}; +/// A spendable output. #[derive(Clone, Debug)] pub struct SpendableOutput { + /// The scalar offset to obtain the key usable to spend this output. + /// Enables HDKD systems. pub offset: Scalar, + /// The output to spend. pub output: TxOut, + /// The TX ID and vout of the output to spend. pub outpoint: OutPoint, } impl SpendableOutput { + /// Obtain a unique ID for this output. pub fn id(&self) -> [u8; 36] { serialize(&self.outpoint).try_into().unwrap() } + /// Read a SpendableOutput from a generic satisfying Read. pub fn read(r: &mut R) -> io::Result { Ok(SpendableOutput { offset: Secp256k1::read_F(r)?, @@ -46,14 +53,22 @@ impl SpendableOutput { }) } + /// Write a SpendableOutput to a generic satisfying Write. + pub fn write(&self, w: &mut W) -> io::Result<()> { + w.write_all(&self.offset.to_bytes())?; + w.write_all(&serialize(&self.output))?; + w.write_all(&serialize(&self.outpoint)) + } + + /// Serialize a SpendableOutput to a Vec. pub fn serialize(&self) -> Vec { - let mut res = self.offset.to_bytes().to_vec(); - self.output.consensus_encode(&mut res).unwrap(); - self.outpoint.consensus_encode(&mut res).unwrap(); + let mut res = vec![]; + self.write(&mut res).unwrap(); res } } +/// A signable transaction, clone-able across attempts. #[derive(Clone, Debug)] pub struct SignableTransaction(Transaction, Vec, Vec); @@ -82,6 +97,7 @@ impl SignableTransaction { u64::try_from(tx.weight()).unwrap() } + /// Create a new signable-transaction. pub fn new( mut inputs: Vec, payments: &[(Address, u64)], @@ -130,6 +146,7 @@ impl SignableTransaction { )) } + /// Create a multisig machine for this transaction. pub async fn multisig( self, keys: ThresholdKeys, @@ -165,6 +182,7 @@ impl SignableTransaction { } } +/// A FROST signing machine to produce a Bitcoin transaction. pub struct TransactionMachine { tx: SignableTransaction, transcript: RecommendedTranscript,