-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: use k256 and simplify bip32
- Loading branch information
James Prestwich
committed
Jan 5, 2021
1 parent
ca69d8c
commit 8ed0d5a
Showing
37 changed files
with
3,567 additions
and
1,506 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
[package] | ||
name = "coins-bip32" | ||
version = "0.1.0-beta.0" | ||
authors = ["James Prestwich <james@prestwi.ch>"] | ||
edition = "2018" | ||
description = "Bip32 (and related BIPs) in Rust" | ||
repository = "https://github.com/summa-tx/bitcoins-rs" | ||
license = "MIT OR Apache-2.0" | ||
|
||
[dependencies] | ||
thiserror = "1.0" | ||
hmac = "0.7.1" | ||
sha2 = "0.8.0" | ||
bs58 = "0.3.0" | ||
lazy_static = "1.4.0" | ||
coins-core = { path = "../core"} | ||
serde = "1.0.105" | ||
|
||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.secp256k1] | ||
version = "0.17.2" | ||
features = ["recovery"] | ||
|
||
[target.'cfg(target_arch = "wasm32")'.dependencies.libsecp256k1] | ||
git = "https://github.com/paritytech/libsecp256k1.git" | ||
default-features = false | ||
features = ["std", "hmac"] | ||
|
||
[target.'cfg(target_arch = "wasm32")'.dependencies.libsecp256k1-core] | ||
git = "https://github.com/paritytech/libsecp256k1.git" | ||
default-features = false | ||
features = ["std"] | ||
|
||
[dev-dependencies] | ||
hex = "0.4.2" | ||
criterion = "0.3.1" | ||
|
||
[features] | ||
default = ["mainnet"] | ||
rust-secp-static-context = ["libsecp256k1/static-context"] | ||
mainnet = [] | ||
testnet = [] | ||
|
||
[[bench]] | ||
name = "bench" | ||
harness = false |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
use serde::{de::Visitor, ser::SerializeStruct}; | ||
|
||
use crate::enc::XKeyEncoder; | ||
|
||
/// The default encoder, selected by feature flag | ||
#[cfg(feature = "mainnet")] | ||
pub type Encoder = crate::enc::MainnetEncoder; | ||
|
||
/// The default encoder, selected by feature flag | ||
#[cfg(feature = "testnet")] | ||
pub type Encoder = crate::enc::TestnetEncoder; | ||
|
||
impl std::str::FromStr for crate::XPriv { | ||
type Err = crate::Bip32Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
Encoder::xpriv_from_base58(s, Some(&crate::curve::BACKEND)) | ||
} | ||
} | ||
|
||
impl std::str::FromStr for crate::XPub { | ||
type Err = crate::Bip32Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
Encoder::xpub_from_base58(s, Some(&crate::curve::BACKEND)) | ||
} | ||
} | ||
|
||
impl serde::Serialize for crate::XPub { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
let encoded = | ||
Encoder::xpub_to_base58(self).map_err(|e| serde::ser::Error::custom(e.to_string()))?; | ||
serializer.serialize_str(&encoded) | ||
} | ||
} | ||
|
||
impl<'de> serde::Deserialize<'de> for crate::XPub { | ||
fn deserialize<D>(deserializer: D) -> Result<crate::XPub, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
let s: &str = serde::Deserialize::deserialize(deserializer)?; | ||
Encoder::xpub_from_base58(s, Some(crate::Secp256k1::static_ref())) | ||
.map_err(|e| serde::de::Error::custom(e.to_string())) | ||
} | ||
} | ||
|
||
impl serde::Serialize for crate::XPriv { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
let encoded = | ||
Encoder::xpriv_to_base58(self).map_err(|e| serde::ser::Error::custom(e.to_string()))?; | ||
serializer.serialize_str(&encoded) | ||
} | ||
} | ||
|
||
impl<'de> serde::Deserialize<'de> for crate::XPriv { | ||
fn deserialize<D>(deserializer: D) -> Result<crate::XPriv, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
let s: &str = serde::Deserialize::deserialize(deserializer)?; | ||
Encoder::xpriv_from_base58(s, Some(crate::Secp256k1::static_ref())) | ||
.map_err(|e| serde::de::Error::custom(e.to_string())) | ||
} | ||
} | ||
|
||
impl serde::Serialize for crate::DerivedXPriv { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
let mut state = serializer.serialize_struct("DerivedXPriv", 2)?; | ||
state.serialize_field("derivation", &self.derivation)?; | ||
state.serialize_field("xpriv", &self.xpriv)?; | ||
state.end() | ||
} | ||
} | ||
|
||
struct DerivedXPrivVisitor; | ||
|
||
impl<'de> Visitor<'de> for DerivedXPrivVisitor { | ||
type Value = crate::DerivedXPriv; | ||
|
||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
formatter.write_str("struct DerivedXPriv") | ||
} | ||
|
||
fn visit_seq<V>(self, mut seq: V) -> Result<crate::DerivedXPriv, V::Error> | ||
where | ||
V: serde::de::SeqAccess<'de>, | ||
{ | ||
let xpriv = seq | ||
.next_element()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; | ||
let derivation = seq | ||
.next_element()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; | ||
Ok(crate::DerivedXPriv { xpriv, derivation }) | ||
} | ||
|
||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> | ||
where | ||
V: serde::de::MapAccess<'de>, | ||
{ | ||
let mut xpriv = None; | ||
let mut derivation = None; | ||
|
||
#[derive(serde::Deserialize)] | ||
#[serde(field_identifier, rename_all = "lowercase")] | ||
enum Field { | ||
XPriv, | ||
Derivation, | ||
} | ||
|
||
while let Some(key) = map.next_key()? { | ||
match key { | ||
Field::XPriv => { | ||
if xpriv.is_some() { | ||
return Err(serde::de::Error::duplicate_field("xpriv")); | ||
} | ||
xpriv = Some(map.next_value()?); | ||
} | ||
Field::Derivation => { | ||
if derivation.is_some() { | ||
return Err(serde::de::Error::duplicate_field("derivation")); | ||
} | ||
derivation = Some(map.next_value()?); | ||
} | ||
} | ||
} | ||
|
||
let xpriv = xpriv.ok_or_else(|| serde::de::Error::missing_field("xpriv"))?; | ||
let derivation = derivation.ok_or_else(|| serde::de::Error::missing_field("derivation"))?; | ||
|
||
Ok(crate::DerivedXPriv { xpriv, derivation }) | ||
} | ||
} | ||
|
||
impl<'de> serde::Deserialize<'de> for crate::DerivedXPriv { | ||
fn deserialize<D>(deserializer: D) -> Result<crate::DerivedXPriv, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
const FIELDS: &[&str] = &["xpriv", "derivation"]; | ||
deserializer.deserialize_struct("Duration", FIELDS, DerivedXPrivVisitor) | ||
} | ||
} | ||
|
||
impl serde::Serialize for crate::DerivedXPub { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
let mut state = serializer.serialize_struct("DerivedXPub", 2)?; | ||
state.serialize_field("derivation", &self.derivation)?; | ||
state.serialize_field("xpub", &self.xpub)?; | ||
state.end() | ||
} | ||
} | ||
|
||
struct DerivedXPubVisitor; | ||
|
||
impl<'de> Visitor<'de> for DerivedXPubVisitor { | ||
type Value = crate::DerivedXPub; | ||
|
||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
formatter.write_str("struct DerivedXPub") | ||
} | ||
|
||
fn visit_seq<V>(self, mut seq: V) -> Result<crate::DerivedXPub, V::Error> | ||
where | ||
V: serde::de::SeqAccess<'de>, | ||
{ | ||
let xpub = seq | ||
.next_element()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; | ||
let derivation = seq | ||
.next_element()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; | ||
Ok(crate::DerivedXPub { xpub, derivation }) | ||
} | ||
|
||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> | ||
where | ||
V: serde::de::MapAccess<'de>, | ||
{ | ||
let mut xpub = None; | ||
let mut derivation = None; | ||
|
||
#[derive(serde::Deserialize)] | ||
#[serde(field_identifier, rename_all = "lowercase")] | ||
enum Field { | ||
XPub, | ||
Derivation, | ||
} | ||
|
||
while let Some(key) = map.next_key()? { | ||
match key { | ||
Field::XPub => { | ||
if xpub.is_some() { | ||
return Err(serde::de::Error::duplicate_field("xpub")); | ||
} | ||
xpub = Some(map.next_value()?); | ||
} | ||
Field::Derivation => { | ||
if derivation.is_some() { | ||
return Err(serde::de::Error::duplicate_field("derivation")); | ||
} | ||
derivation = Some(map.next_value()?); | ||
} | ||
} | ||
} | ||
|
||
let xpub = xpub.ok_or_else(|| serde::de::Error::missing_field("xpub"))?; | ||
let derivation = derivation.ok_or_else(|| serde::de::Error::missing_field("derivation"))?; | ||
|
||
Ok(crate::DerivedXPub { xpub, derivation }) | ||
} | ||
} | ||
|
||
impl<'de> serde::Deserialize<'de> for crate::DerivedXPub { | ||
fn deserialize<D>(deserializer: D) -> Result<crate::DerivedXPub, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
const FIELDS: &[&str] = &["xpub", "derivation"]; | ||
deserializer.deserialize_struct("Duration", FIELDS, DerivedXPubVisitor) | ||
} | ||
} |
Oops, something went wrong.