From 27f1da36214a21d2c97a7d9c6494e98633cbe1ff Mon Sep 17 00:00:00 2001 From: kaiwitt Date: Sat, 28 Aug 2021 09:27:29 +0200 Subject: [PATCH 1/3] Implement xor trait for bip39::Mnemonic --- Cargo.toml | 2 +- src/lib.rs | 74 +++++++++++++++++++++++++++++------------------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbaf3f4..57d46c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,4 @@ publish = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bip39 = "1.0.1" \ No newline at end of file +bip39 = "1.0.*" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7f9deba..e5f3a01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ //! # seed-xor //! //! seed-xor builds on top of [rust-bip39](https://github.com/rust-bitcoin/rust-bip39/) -//! and lets you XOR bip39 mnemonics as defined in [Coldcards docs](https://github.com/Coldcard/firmware/blob/master/docs/seed-xor.md). +//! and lets you XOR bip39 mnemonics as described in [Coldcards docs](https://github.com/Coldcard/firmware/blob/master/docs/seed-xor.md). //! //! //! It is also possible to XOR mnemonics with differing numbers of words. -//! For this the shorter one will be extended with 0s during the XOR calculation. +//! For this the xored value takes on the entropy surplus of the longer seed. //! //! //! ## Example @@ -36,39 +36,17 @@ use std::{ str::FromStr, }; -use bip39::Mnemonic as Inner; - -/// Wrapper for a [bip39::Mnemonic] which is aliased as `Inner`. -#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)] -pub struct Mnemonic { - /// Actual [bip39::Mnemonic] which is wrapped to be able to implement the XOR operator. - inner: Inner, +/// Trait for a `XOR`. +pub trait SeedXor { + /// XOR two values without consuming them. + fn xor(&self, rhs: &Self) -> Self; } -impl Mnemonic { - /// Private constructor. - fn new(inner: Inner) -> Self { - Mnemonic { inner } - } - - /// Access the private inner [bip39::Mnemonic] for more functionality. - pub fn inner(&self) -> &Inner { - &self.inner - } - - /// Wrapper for the same method as in [bip39::Mnemonic]. - pub fn from_entropy(entropy: &[u8]) -> Result { - match Inner::from_entropy(entropy) { - Ok(inner) => Ok(Mnemonic::new(inner)), - Err(err) => Err(err), - } - } - - /// XOR two [Mnemonic]s without consuming them. - /// If consumption is not of relevance the XOR operator `^` and XOR assigner `^=` can be used as well. +impl SeedXor for bip39::Mnemonic { + /// XOR self with another [bip39::Mnemonic] without consuming it or itself. fn xor(&self, rhs: &Self) -> Self { - let mut entropy = self.inner.to_entropy(); - let xor_values = rhs.inner.to_entropy(); + let mut entropy = self.to_entropy(); + let xor_values = rhs.to_entropy(); // XOR each Byte entropy @@ -83,7 +61,35 @@ impl Mnemonic { // We unwrap here because entropy has either as many Bytes // as self or rhs and both are valid mnemonics. - Mnemonic::from_entropy(&entropy).unwrap() + bip39::Mnemonic::from_entropy(&entropy).unwrap() + } +} + +/// Wrapper for a [bip39::Mnemonic] for the implementation of `^` and `^=` operators. +#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)] +pub struct Mnemonic { + /// Actual [bip39::Mnemonic] which is wrapped to be able to implement the XOR operator. + pub inner: bip39::Mnemonic, +} + +impl Mnemonic { + /// Private constructor. + fn new(inner: bip39::Mnemonic) -> Self { + Mnemonic { inner } + } + + /// Wrapper for the same method as in [bip39::Mnemonic]. + pub fn from_entropy(entropy: &[u8]) -> Result { + match bip39::Mnemonic::from_entropy(entropy) { + Ok(inner) => Ok(Mnemonic::new(inner)), + Err(err) => Err(err), + } + } + + /// XOR two [Mnemonic]s without consuming them. + /// If consumption is not of relevance the XOR operator `^` and XOR assigner `^=` can be used as well. + fn xor(&self, rhs: &Self) -> Self { + Mnemonic::new(self.inner.xor(&rhs.inner)) } } @@ -91,7 +97,7 @@ impl FromStr for Mnemonic { type Err = bip39::Error; fn from_str(mnemonic: &str) -> Result::Err> { - match Inner::from_str(mnemonic) { + match bip39::Mnemonic::from_str(mnemonic) { Ok(inner) => Ok(Mnemonic::new(inner)), Err(err) => Err(err), } From 121bd814c0c3713ec8a835a7f48a7a91e2dfc2c3 Mon Sep 17 00:00:00 2001 From: kaiwitt Date: Sat, 28 Aug 2021 09:29:53 +0200 Subject: [PATCH 2/3] Bump version to v1.0.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7448778..a55b654 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,7 +34,7 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "seed-xor" -version = "0.1.0" +version = "1.0.0" dependencies = [ "bip39", ] diff --git a/Cargo.toml b/Cargo.toml index 57d46c8..b8d2208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "seed-xor" -version = "0.1.0" +version = "1.0.0" edition = "2018" authors = ["KaiWitt "] description = "XOR bip39 mnemonics." From e3541e5c41503de86575890308b213fda28488d9 Mon Sep 17 00:00:00 2001 From: kaiwitt Date: Sat, 28 Aug 2021 09:33:24 +0200 Subject: [PATCH 3/3] Add GitHub action --- workflows/cargo.yml | 17 +++++++++++++++++ workflows/clippy.yml | 12 ++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 workflows/cargo.yml create mode 100644 workflows/clippy.yml diff --git a/workflows/cargo.yml b/workflows/cargo.yml new file mode 100644 index 0000000..9ec5201 --- /dev/null +++ b/workflows/cargo.yml @@ -0,0 +1,17 @@ +on: [push] + +name: CI + +jobs: + build_and_test: + name: cargo_test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - uses: actions-rs/cargo@v1 + with: + command: test + args: --release --all-features \ No newline at end of file diff --git a/workflows/clippy.yml b/workflows/clippy.yml new file mode 100644 index 0000000..6010bf2 --- /dev/null +++ b/workflows/clippy.yml @@ -0,0 +1,12 @@ +on: push +name: Clippy check +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: rustup component add clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-features