keypair generation in progress

This commit is contained in:
debris 2016-08-18 12:56:18 +02:00
parent d7f650db51
commit e39f37fac7
9 changed files with 159 additions and 27 deletions

View File

@ -1,19 +0,0 @@
//! A Bitcoin address, or simply address, is an identifier of 26-35 alphanumeric characters, beginning with the number 1
//! or 3, that represents a possible destination for a bitcoin payment.
//!
//! https://en.bitcoin.it/wiki/Address
/// There are two address formats currently in use.
/// https://bitcoin.org/en/developer-reference#address-conversion
pub enum Format {
/// Pay to PubKey Hash
/// Common P2PKH which begin with the number 1, eg: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2.
/// https://bitcoin.org/en/glossary/p2pkh-address
P2PKH,
/// Pay to Script Hash
/// Newer P2SH type starting with the number 3, eg: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy.
/// https://bitcoin.org/en/glossary/p2sh-address
P2SH,
}

71
src/keys/address.rs Normal file
View File

@ -0,0 +1,71 @@
//! A Bitcoin address, or simply address, is an identifier of 26-35 alphanumeric characters, beginning with the number 1
//! or 3, that represents a possible destination for a bitcoin payment.
//!
//! https://en.bitcoin.it/wiki/Address
use std::fmt;
use std::ops::Deref;
use base58::ToBase58;
use network::Network;
use hash::H160;
use keys::{DisplayLayout, checksum};
/// There are two address formats currently in use.
/// https://bitcoin.org/en/developer-reference#address-conversion
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Type {
/// Pay to PubKey Hash
/// Common P2PKH which begin with the number 1, eg: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2.
/// https://bitcoin.org/en/glossary/p2pkh-address
P2PKH,
/// Pay to Script Hash
/// Newer P2SH type starting with the number 3, eg: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy.
/// https://bitcoin.org/en/glossary/p2sh-address
P2SH,
}
#[derive(Debug, PartialEq)]
pub struct Address {
/// The type of the address.
pub kind: Type,
/// The network of the address.
pub network: Network,
/// Public key hash.
pub hash: H160,
}
pub struct AddressDisplayLayout([u8; 25]);
impl Deref for AddressDisplayLayout {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DisplayLayout for Address {
type Target = AddressDisplayLayout;
fn layout(&self) -> Self::Target {
let mut result = [0u8; 25];
result[0] = match (self.network, self.kind) {
(Network::Mainnet, Type::P2PKH) => 0,
(Network::Mainnet, Type::P2SH) => 5,
(Network::Testnet, Type::P2PKH) => 111,
(Network::Testnet, Type::P2SH) => 196,
};
result[1..21].copy_from_slice(&self.hash);
let cs = checksum(&result[0..21]);
result[21..25].copy_from_slice(&cs);
AddressDisplayLayout(result)
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.layout().to_base58().fmt(f)
}
}

9
src/keys/checksum.rs Normal file
View File

@ -0,0 +1,9 @@
use crypto::dhash;
/// Data checksum
pub fn checksum(data: &[u8]) -> [u8; 4] {
let mut result = [0u8; 4];
// TODO: check if this checksum is valid
result.copy_from_slice(&dhash(data)[28..]);
result
}

7
src/keys/display.rs Normal file
View File

@ -0,0 +1,7 @@
use std::ops::Deref;
pub trait DisplayLayout {
type Target: Deref<Target = [u8]>;
fn layout(&self) -> Self::Target;
}

View File

@ -1,10 +1,21 @@
//! Bitcoin KeyPair
//!
//! Fields:
//! - secret - 32 bytes
//! - public - 65 bytes
//! - private - secret with additional network identifier (and compressed flag?)
//! - address_hash - 20 bytes derived from public
//! - address - address_hash with network identifier and format type
use std::fmt; use std::fmt;
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::ToHex;
use rcrypto::sha2::Sha256; use rcrypto::sha2::Sha256;
use rcrypto::ripemd160::Ripemd160; use rcrypto::ripemd160::Ripemd160;
use rcrypto::digest::Digest; use rcrypto::digest::Digest;
use secp256k1::key; use secp256k1::key;
use keys::{Secret, Public, Error, SECP256K1, Address}; use hash::H160;
use network::Network;
use keys::{Secret, Public, Error, SECP256K1, Address, Type};
pub struct KeyPair { pub struct KeyPair {
secret: Secret, secret: Secret,
@ -51,7 +62,7 @@ impl KeyPair {
} }
} }
pub fn address(&self) -> Address { pub fn address_hash(&self) -> H160 {
let mut tmp = [0u8; 32]; let mut tmp = [0u8; 32];
let mut result = [0u8; 20]; let mut result = [0u8; 20];
let mut sha2 = Sha256::new(); let mut sha2 = Sha256::new();
@ -62,12 +73,20 @@ impl KeyPair {
rmd.result(&mut result); rmd.result(&mut result);
result result
} }
pub fn address(&self, network: Network) -> Address {
Address {
kind: Type::P2PKH,
network: network,
hash: self.address_hash(),
}
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::KeyPair; use super::KeyPair;
use base58::{ToBase58, FromBase58}; use base58::{FromBase58};
#[test] #[test]
fn test_generating_address() { fn test_generating_address() {
@ -78,6 +97,6 @@ mod tests {
let mut address = [0u8; 20]; let mut address = [0u8; 20];
address.copy_from_slice(&"16meyfSoQV6twkAAxPe51RtMVz7PGRmWna".from_base58().unwrap()[1..21]); address.copy_from_slice(&"16meyfSoQV6twkAAxPe51RtMVz7PGRmWna".from_base58().unwrap()[1..21]);
let kp = KeyPair::from_secret(secret).unwrap(); let kp = KeyPair::from_secret(secret).unwrap();
assert_eq!(kp.address(), address); assert_eq!(kp.address_hash(), address);
} }
} }

View File

@ -1,13 +1,20 @@
mod address;
mod checksum;
pub mod display;
pub mod generator; pub mod generator;
pub mod keypair; pub mod keypair;
mod error; mod error;
mod private;
use secp256k1; use secp256k1;
use hash::{H160, H256, H520}; use hash::{H256, H520};
pub use self::address::{Type, Address};
pub use self::checksum::checksum;
pub use self::display::DisplayLayout;
pub use self::keypair::KeyPair; pub use self::keypair::KeyPair;
pub use self::error::Error; pub use self::error::Error;
pub use self::private::Private;
pub type Address = H160;
pub type Secret = H256; pub type Secret = H256;
pub type Public = H520; pub type Public = H520;

39
src/keys/private.rs Normal file
View File

@ -0,0 +1,39 @@
use std::fmt;
use base58::ToBase58;
use network::Network;
use keys::{Secret, DisplayLayout};
#[derive(Debug, PartialEq)]
pub struct Private {
/// The network on which this key should be used.
pub network: Network,
/// ECDSA key.
pub secret: Secret,
/// True if this private key represents a compressed address.
pub compressed: bool,
}
impl DisplayLayout for Private {
type Target = Vec<u8>;
fn layout(&self) -> Self::Target {
let mut result = vec![];
let network_byte = match self.network {
Network::Mainnet => 128,
Network::Testnet => 239,
};
result.push(network_byte);
result.extend(&self.secret);
if self.compressed {
result.push(1);
}
result
}
}
impl fmt::Display for Private {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.layout().to_base58().fmt(f)
}
}

View File

@ -10,7 +10,6 @@ extern crate secp256k1;
extern crate base58; extern crate base58;
pub mod keys; pub mod keys;
pub mod address;
pub mod block; pub mod block;
pub mod block_header; pub mod block_header;
pub mod compact_integer; pub mod compact_integer;

View File

@ -5,7 +5,7 @@ const MAGIC_TESTNET: u32 = 0x0709110B;
/// Bitcoin network /// Bitcoin network
/// https://bitcoin.org/en/glossary/mainnet /// https://bitcoin.org/en/glossary/mainnet
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum Network { pub enum Network {
/// The original and main network for Bitcoin transactions, where satoshis have real economic value. /// The original and main network for Bitcoin transactions, where satoshis have real economic value.
Mainnet, Mainnet,