keypair generation in progress
This commit is contained in:
parent
d7f650db51
commit
e39f37fac7
|
@ -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,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub trait DisplayLayout {
|
||||||
|
type Target: Deref<Target = [u8]>;
|
||||||
|
|
||||||
|
fn layout(&self) -> Self::Target;
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue