bless
This commit is contained in:
parent
891f93de6b
commit
6dcf11c718
@ -1,5 +1,5 @@
|
||||
age-encryption.org/v1
|
||||
-> scrypt FP9Jzf9WMGgQj2HZPAbuDw 14
|
||||
i+HlcYKckQXUKAtoY8SIjJUz15IE2GucgQM0sZxLx78
|
||||
--- 5JVy3rsJpvCXTl41B6/k/aC0HqoAdyfH4I6efffwr/w
|
||||
-éŰÂ|Q÷ÚúÇ‘-D‰3´<%’Ą|~<7E>¨<07><>韥ť)ęŔÂ"ŠČ+ůńá(Ýţ°}<7D>ÂéëKüv”É<>'#<23><>°SťtUuîX,’ů|‡ ďŚÝZ>CËőĐ
šó•Ú:Y”#úÔ:Áť×Ô•Ţă LNMĽô“Ë‚ěŐÖ*-´¸čôăHnD<6E>˛ŁŃU«O›cÚoůJ×6ŠţŁ^ĺłc¸ňŽý«¦X<>0ŘĽp¸–K\’š—ę~âuX|Ě; |ßÎ7D¸MÄD‡;_źlő`’K†^Ž+ěAË
|
||||
-> scrypt qz/wL52nh3MG/kb96jc2Mg 13
|
||||
auC858eJBPN/QknA7lj7CdnrmKEm8EOSasOQpBkkJ/c
|
||||
--- K1MwOdhmY33yGi7USChiazGeOj9uUGKCYvVOltWSA7A
|
||||
,-¨íÒ¦sf$LàoõÁzžìÇA3Á³ºvbÉ„¡r4Ü‘¶ùÀ!ÕHæDäâb÷±¤IBêó*<2A>5<EFBFBD>s<EFBFBD>ÚÓ
|
||||
@ -15,6 +15,7 @@ mod tests {
|
||||
|
||||
use std::io::{ Read, Write };
|
||||
|
||||
#[test]
|
||||
fn encrypt() {
|
||||
let passphrase = age::secrecy::SecretString::from("password");
|
||||
|
||||
@ -25,10 +26,10 @@ mod tests {
|
||||
private_key: "thisisprivate".to_string()
|
||||
};
|
||||
|
||||
let b = bincode::serde::encode_to_vec::<Wallet, bincode::config::Configuration>(wallet, bincode::config::Configuration::default()).unwrap();
|
||||
let b = bincode::serde::encode_to_vec::<Wallet, bincode::config::Configuration>(wallet, bincode::config::standard()).unwrap();
|
||||
|
||||
let encryptor = age::Encryptor::with_user_passphrase(passphrase);
|
||||
let file = std::fs::OpenOptions::new().create(true).write(true).open(OUT_FILE).unwrap();
|
||||
let file = std::fs::OpenOptions::new().create(true).truncate(true).write(true).open(OUT_FILE).unwrap();
|
||||
let mut stream = encryptor.wrap_output(file).unwrap();
|
||||
stream.write_all(&b).unwrap();
|
||||
stream.finish().unwrap();
|
||||
@ -47,7 +48,7 @@ mod tests {
|
||||
|
||||
decryptor.decrypt(std::iter::once(&identity as &dyn age::Identity)).unwrap().read_to_end(&mut buf).unwrap();
|
||||
|
||||
let (wallet, _): (Wallet, usize) = bincode::serde::decode_from_slice::<Wallet, bincode::config::Configuration>(&buf, bincode::config::Configuration::default()).unwrap();
|
||||
let (wallet, _): (Wallet, usize) = bincode::serde::decode_from_slice::<Wallet, bincode::config::Configuration>(&buf, bincode::config::standard()).unwrap();
|
||||
|
||||
dbg!(&wallet);
|
||||
}
|
||||
|
||||
2
wallet/Cargo.lock
generated
2
wallet/Cargo.lock
generated
@ -1693,8 +1693,10 @@ name = "wallet"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"age",
|
||||
"bincode",
|
||||
"hex",
|
||||
"k256",
|
||||
"serde",
|
||||
"sha3",
|
||||
"shared",
|
||||
"thiserror 2.0.16",
|
||||
|
||||
@ -5,8 +5,10 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
age = { version = "0.11.1", features = ["cli-common"] }
|
||||
bincode = { version = "2.0.1", features = ["serde"] }
|
||||
hex = "0.4.3"
|
||||
k256 = { version = "0.13.4", features = ["serde"] }
|
||||
k256 = { version = "0.13.4", features = ["ecdsa-core", "serde"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
sha3 = "0.10.8"
|
||||
shared = { path = "../shared" }
|
||||
thiserror = "2.0.16"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use age::Identity;
|
||||
use bincode::{Decode, Encode};
|
||||
use k256::sha2::Digest;
|
||||
use k256::ecdsa::{
|
||||
self,
|
||||
@ -5,13 +7,17 @@ use k256::ecdsa::{
|
||||
VerifyingKey,
|
||||
RecoveryId,
|
||||
Signature,
|
||||
signature::Verifier,
|
||||
};
|
||||
use shared::core::{ Transaction, SignedTransaction, Address, };
|
||||
use k256::elliptic_curve::rand_core::OsRng;
|
||||
use sha3::Keccak256;
|
||||
|
||||
use std::io::Read;
|
||||
use std::path;
|
||||
|
||||
static BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum WalletError {
|
||||
#[error("No Private Key present in Wallet")]
|
||||
@ -20,6 +26,12 @@ pub enum WalletError {
|
||||
#[error("Signature error: {0}")]
|
||||
SignatureError(#[from] ecdsa::Error),
|
||||
|
||||
#[error("Encryption Error: {0}")]
|
||||
EncryptionError(#[from] age::EncryptError),
|
||||
|
||||
#[error("Decryption Error: {0}")]
|
||||
DecryptionError(#[from] age::DecryptError),
|
||||
|
||||
#[error("Provided Recovery ID is invalid: {0}")]
|
||||
InvalidRecoveryId(u8),
|
||||
|
||||
@ -27,26 +39,39 @@ pub enum WalletError {
|
||||
IO(#[from] std::io::Error),
|
||||
|
||||
#[error("")]
|
||||
InvalidHashLength
|
||||
InvalidHashLength,
|
||||
|
||||
#[error("Passphrase Error: {0}")]
|
||||
PassphraseError(String),
|
||||
|
||||
#[error("Decode Error: {0}")]
|
||||
DecodeError(#[from] bincode::error::DecodeError),
|
||||
|
||||
#[error("Encode Error: {0}")]
|
||||
EncodeError(#[from] bincode::error::EncodeError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Encode, Decode)]
|
||||
pub struct Wallet {
|
||||
address: Address,
|
||||
balance: u64,
|
||||
nonce: u64,
|
||||
private_key: Option<SigningKey>,
|
||||
private_key: [u8; 32],
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
|
||||
fn verify_signature(tx: &SignedTransaction) -> Result<VerifyingKey, WalletError>{
|
||||
if let Some(rec_id) = RecoveryId::from_byte(tx.recovery_id()) {
|
||||
let sig = Signature::from_slice(tx.signature())?;
|
||||
let hash = tx.tx().hash();
|
||||
Ok(VerifyingKey::recover_from_prehash(&hash, &sig, rec_id)?)
|
||||
fn verify_self_signature(&self, sign_tx: &SignedTransaction) -> Result<(), WalletError>{
|
||||
if let Some(rec_id) = RecoveryId::from_byte(sign_tx.recovery_id()) {
|
||||
let sig = Signature::from_slice(sign_tx.signature())?;
|
||||
println!("Signature recovered");
|
||||
let hash = sign_tx.tx().hash();
|
||||
let pub_key = VerifyingKey::recover_from_prehash(&hash, &sig, rec_id).unwrap();
|
||||
// let pub_key = self.public_key()?;
|
||||
println!("pubkey recovered");
|
||||
Ok(pub_key.verify(&hash, &sig).unwrap())
|
||||
} else {
|
||||
Err(WalletError::InvalidRecoveryId(tx.recovery_id()))
|
||||
Err(WalletError::InvalidRecoveryId(sign_tx.recovery_id()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,8 +79,8 @@ impl Wallet {
|
||||
SigningKey::random(&mut OsRng)
|
||||
}
|
||||
|
||||
pub fn address(&self) -> &[u8] {
|
||||
&self.address
|
||||
pub fn address(&self) -> [u8; 20] {
|
||||
self.address.clone()
|
||||
}
|
||||
|
||||
pub fn nonce(&self) -> u64 {
|
||||
@ -63,15 +88,15 @@ impl Wallet {
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> Result<VerifyingKey, WalletError> {
|
||||
if let Some(pk) = &self.private_key {
|
||||
let pk = SigningKey::from_bytes(&self.private_key.into())?;
|
||||
Ok(*pk.verifying_key())
|
||||
} else {
|
||||
Err(WalletError::NoPrivateKeyProvided)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verifying_key_to_address(private_key: &SigningKey) -> Address {
|
||||
let public_key = private_key.verifying_key();
|
||||
pub fn private_key(&self) -> Result<SigningKey, WalletError> {
|
||||
Ok(SigningKey::from_bytes(&self.private_key.into())?)
|
||||
}
|
||||
|
||||
pub fn public_key_to_address(public_key: &VerifyingKey) -> Address {
|
||||
let public_key_bytes = public_key.to_encoded_point(false);
|
||||
let public_key_bytes = public_key_bytes.as_bytes();
|
||||
|
||||
@ -83,44 +108,54 @@ impl Wallet {
|
||||
}
|
||||
|
||||
fn load(path: path::PathBuf) -> Result<Self, WalletError> {
|
||||
let content = std::fs::read(path)?;
|
||||
let file = std::fs::OpenOptions::new().read(true).open(path)?;
|
||||
let decryptor = age::Decryptor::new(file)?;
|
||||
let passphrase = match age::cli_common::read_secret(
|
||||
"Unlock your Wallet",
|
||||
"Please enter the passphrase",
|
||||
Some("confirm?")
|
||||
) {
|
||||
Ok(p) => p,
|
||||
Err(e) => return Err(WalletError::PassphraseError(format!("{e}")))
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
let identity = age::scrypt::Identity::new(passphrase);
|
||||
let mut reader = decryptor.decrypt(std::iter::once(&identity as &dyn Identity))?;
|
||||
reader.read_to_end(&mut buf)?;
|
||||
|
||||
let wallet: Wallet = bincode::decode_from_slice(&buf, BINCODE_CONFIG)?.0;
|
||||
Ok(wallet)
|
||||
}
|
||||
|
||||
fn new(pk: Option<SigningKey>) -> Self {
|
||||
let address = if let Some(pk) = &pk {
|
||||
Self::verifying_key_to_address(pk)
|
||||
} else {
|
||||
Address::default()
|
||||
};
|
||||
fn new() -> Self {
|
||||
let pk = Wallet::generate_private_key();
|
||||
let address = Self::public_key_to_address(&pk.verifying_key());
|
||||
Self {
|
||||
nonce: 0,
|
||||
balance: 0,
|
||||
address,
|
||||
private_key: pk
|
||||
private_key: pk.to_bytes().into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign(&self, transaction: Transaction) -> Result<SignedTransaction, WalletError> {
|
||||
let hash = transaction.hash();
|
||||
if let Some(pk) = &self.private_key {
|
||||
let pk = SigningKey::from_bytes(&self.private_key.into())?;
|
||||
let (signature, recovery_id) = pk.sign_prehash_recoverable(&hash)?;
|
||||
Ok(SignedTransaction::new(
|
||||
transaction,
|
||||
signature.to_bytes().into(),
|
||||
recovery_id.into()
|
||||
))
|
||||
} else {
|
||||
Err(WalletError::NoPrivateKeyProvided)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acc_new_sign_no_key() {
|
||||
let wallet = Wallet::new(None);
|
||||
let wallet = Wallet::new();
|
||||
let to_address: [u8; 20] = [1u8; 20];
|
||||
let mut wallet_addr = [0u8; 20];
|
||||
wallet_addr.copy_from_slice(wallet.address());
|
||||
wallet_addr.copy_from_slice(&wallet.address());
|
||||
let tx = Transaction::new(
|
||||
wallet_addr,
|
||||
to_address,
|
||||
@ -132,30 +167,64 @@ fn acc_new_sign_no_key() {
|
||||
assert!(matches!(ret, Err(WalletError::NoPrivateKeyProvided)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acc_new_sign_with_key() -> Result<(), WalletError> {
|
||||
let pk = Wallet::generate_private_key();
|
||||
let wallet = Wallet::new(Some(pk));
|
||||
let orig_public_key = wallet.public_key()?;
|
||||
let mut wallet_addr = [0u8; 20];
|
||||
let to_address = [1u8; 20];
|
||||
wallet_addr.copy_from_slice(wallet.address());
|
||||
let tx = Transaction::new(
|
||||
wallet_addr,
|
||||
to_address,
|
||||
500,
|
||||
wallet.nonce(),
|
||||
format!("")
|
||||
);
|
||||
let ret = wallet.sign(tx);
|
||||
assert!(matches!(ret, Ok(SignedTransaction{..})));
|
||||
let msg = ret.unwrap();
|
||||
let pub_key = Wallet::verify_signature(&msg)?;
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const WALLET_PATH: &str = "./wallet.age";
|
||||
|
||||
let orig_pub_key_bytes = orig_public_key.to_encoded_point(false);
|
||||
let new_pub_key_bytes = pub_key.to_encoded_point(false);
|
||||
use std::io::Write;
|
||||
|
||||
assert_eq!(orig_pub_key_bytes, new_pub_key_bytes);
|
||||
use age::secrecy::SecretString;
|
||||
|
||||
use super::*;
|
||||
|
||||
mod new {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn wallet_new() -> Result<(), WalletError> {
|
||||
let wallet = Wallet::new();
|
||||
let passphrase = SecretString::from("password");
|
||||
|
||||
let bin_wallet = bincode::encode_to_vec::<Wallet, _>(wallet, BINCODE_CONFIG)?;
|
||||
|
||||
let file = std::fs::OpenOptions::new().create(true).write(true).truncate(true).open(WALLET_PATH)?;
|
||||
let encryptor = age::Encryptor::with_user_passphrase(passphrase);
|
||||
let mut writer = encryptor.wrap_output(file)?;
|
||||
writer.write_all(&bin_wallet)?;
|
||||
writer.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
mod load {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn wallet_load() -> Result<(), WalletError> {
|
||||
let wallet = Wallet::load(WALLET_PATH.into())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod sign {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn load_sign_verify() -> Result<(), WalletError> {
|
||||
let wallet = Wallet::load(WALLET_PATH.into())?;
|
||||
|
||||
let tx = Transaction::new(wallet.address(), Default::default(), 500, wallet.nonce() + 1, "This is my data".to_string());
|
||||
// let mut hash = Keccak256::new();
|
||||
// hash.update(tx.data());
|
||||
let hash = tx.hash();
|
||||
let pk: ecdsa::SigningKey = wallet.private_key()?;
|
||||
let (signature, recovery_id) = pk.sign_recoverable(&hash)?;
|
||||
// let sig_tx = SignedTransaction::new(tx, signature.to_bytes().into(), recovery_id.into());
|
||||
let vk = pk.verifying_key();
|
||||
vk.verify(&hash, &signature).unwrap();
|
||||
|
||||
// wallet.verify_self_signature(&sig_tx)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
wallet/wallet.age
Normal file
BIN
wallet/wallet.age
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user