mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-05 23:03:06 +00:00
implement public and private keys
This commit is contained in:
parent
54dd9aa814
commit
703a127f0e
@ -11,6 +11,7 @@ program-methods = { path = "program_methods" }
|
||||
serde = "1.0.219"
|
||||
serde_cbor = "0.11.2"
|
||||
sha2 = "0.10.9"
|
||||
secp256k1 = "0.31.1"
|
||||
|
||||
[dev-dependencies]
|
||||
test-program-methods = { path = "test_program_methods" }
|
||||
|
||||
@ -14,7 +14,7 @@ impl Address {
|
||||
|
||||
pub fn from_public_key(public_key: &PublicKey) -> Self {
|
||||
// TODO: implement
|
||||
Address::new([public_key.0; 32])
|
||||
Address::new(public_key.0)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &[u8; 32] {
|
||||
|
||||
@ -13,4 +13,7 @@ pub enum NssaError {
|
||||
|
||||
#[error("Serialization error: {0}")]
|
||||
InstructionSerializationError(String),
|
||||
|
||||
#[error("Invalid private key")]
|
||||
InvalidPrivateKey,
|
||||
}
|
||||
|
||||
@ -21,8 +21,7 @@ impl Program {
|
||||
pub fn serialize_instruction<T: Serialize>(
|
||||
instruction: T,
|
||||
) -> Result<InstructionData, NssaError> {
|
||||
to_vec(&instruction)
|
||||
.map_err(|e| NssaError::InstructionSerializationError(e.to_string()))
|
||||
to_vec(&instruction).map_err(|e| NssaError::InstructionSerializationError(e.to_string()))
|
||||
}
|
||||
|
||||
pub(crate) fn execute(
|
||||
|
||||
@ -7,9 +7,39 @@ pub struct WitnessSet {
|
||||
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
|
||||
}
|
||||
|
||||
fn message_to_bytes(_message: &Message) -> Vec<u8> {
|
||||
//TODO: implement
|
||||
vec![0, 0]
|
||||
const MESSAGE_ENCODING_PREFIX: &[u8; 19] = b"NSSA/v0.1/TxMessage";
|
||||
|
||||
/// Serializes a `Message` into bytes in the following layout:
|
||||
/// TAG || <program_id> (bytes LE) * 8 || addresses_len (4 bytes LE) || addresses (32 bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes * M) || instruction_data_len || instruction_data (4 bytes * K)
|
||||
/// Integers and words are encoded in little-endian byte order, and fields appear in the above order.
|
||||
fn message_to_bytes(message: &Message) -> Vec<u8> {
|
||||
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||
// program_id: [u32; 8]
|
||||
for word in &message.program_id {
|
||||
bytes.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
// addresses: Vec<[u8;32]>
|
||||
// serialize length as u32 little endian, then all addresses concatenated
|
||||
let addresses_len = message.addresses.len() as u32;
|
||||
bytes.extend(&addresses_len.to_le_bytes());
|
||||
for addr in &message.addresses {
|
||||
bytes.extend_from_slice(addr.value());
|
||||
}
|
||||
// nonces: Vec<u128>
|
||||
let nonces_len = message.nonces.len() as u32;
|
||||
bytes.extend(&nonces_len.to_le_bytes());
|
||||
for nonce in &message.nonces {
|
||||
bytes.extend(&nonce.to_le_bytes());
|
||||
}
|
||||
// instruction_data: Vec<u32>
|
||||
// serialize length as u32 little endian, then all addresses concatenated
|
||||
let instr_len = message.instruction_data.len() as u32;
|
||||
bytes.extend(&instr_len.to_le_bytes());
|
||||
for word in &message.instruction_data {
|
||||
bytes.extend(&word.to_le_bytes());
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
impl WitnessSet {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::public_transaction::Message;
|
||||
use crate::{error::NssaError, public_transaction::Message};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Signature(pub(crate) u8);
|
||||
@ -9,32 +9,46 @@ pub struct Signature(pub(crate) u8);
|
||||
// TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons
|
||||
// TODO: Implement Zeroize
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PrivateKey(pub(crate) u8);
|
||||
pub struct PrivateKey(pub(crate) [u8; 32]);
|
||||
|
||||
impl PrivateKey {
|
||||
pub fn new(dummy_value: u8) -> Self {
|
||||
Self(dummy_value)
|
||||
fn is_valid_key(value: [u8; 32]) -> bool {
|
||||
secp256k1::SecretKey::from_byte_array(value).is_ok()
|
||||
}
|
||||
|
||||
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaError> {
|
||||
if Self::is_valid_key(value) {
|
||||
Ok(Self(value))
|
||||
} else {
|
||||
Err(NssaError::InvalidPrivateKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Dummy impl. Replace by actual public key.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PublicKey(pub(crate) u8);
|
||||
pub struct PublicKey(pub(crate) [u8; 32]);
|
||||
|
||||
impl PublicKey {
|
||||
pub fn new(key: &PrivateKey) -> Self {
|
||||
// TODO: implement
|
||||
Self(key.0)
|
||||
let value = {
|
||||
let secret_key = secp256k1::SecretKey::from_byte_array(key.0).unwrap();
|
||||
let public_key =
|
||||
secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &secret_key);
|
||||
let (x_only, _) = public_key.x_only_public_key();
|
||||
x_only.serialize()
|
||||
};
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub(crate) fn new(key: &PrivateKey, _message: &[u8]) -> Self {
|
||||
Signature(key.0)
|
||||
Signature(0)
|
||||
}
|
||||
|
||||
pub fn is_valid_for(&self, _message: &Message, public_key: &PublicKey) -> bool {
|
||||
pub fn is_valid_for(&self, _message: &Message, _public_key: &PublicKey) -> bool {
|
||||
// TODO: implement
|
||||
self.0 == public_key.0
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Address, PublicTransaction, V01State, error::NssaError, program::Program, public_transaction,
|
||||
signature::PrivateKey,
|
||||
Address, PublicKey, PublicTransaction, V01State, error::NssaError, program::Program,
|
||||
public_transaction, signature::PrivateKey,
|
||||
};
|
||||
use nssa_core::account::Account;
|
||||
|
||||
@ -14,22 +14,24 @@ fn transfer_transaction(
|
||||
let addresses = vec![from, to];
|
||||
let nonces = vec![nonce];
|
||||
let program_id = Program::authenticated_transfer_program().id();
|
||||
let message = public_transaction::Message::try_new(program_id, addresses, nonces, balance).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, addresses, nonces, balance).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]);
|
||||
PublicTransaction::new(message, witness_set)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transition_from_authenticated_transfer_program_invocation_default_account_destination() {
|
||||
let initial_data = [([1; 32], 100)];
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let address = Address::from_public_key(&PublicKey::new(&key));
|
||||
let initial_data = [(*address.value(), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let from = Address::new(initial_data[0].0);
|
||||
let from_key = PrivateKey(1);
|
||||
let from = address;
|
||||
let to = Address::new([2; 32]);
|
||||
assert_eq!(state.get_account_by_address(&to), Account::default());
|
||||
let balance_to_move = 5;
|
||||
|
||||
let tx = transfer_transaction(from.clone(), from_key, 0, to.clone(), balance_to_move);
|
||||
let tx = transfer_transaction(from.clone(), key, 0, to.clone(), balance_to_move);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
|
||||
assert_eq!(state.get_account_by_address(&from).balance, 95);
|
||||
@ -40,10 +42,12 @@ fn transition_from_authenticated_transfer_program_invocation_default_account_des
|
||||
|
||||
#[test]
|
||||
fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() {
|
||||
let initial_data = [([1; 32], 100)];
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let address = Address::from_public_key(&PublicKey::new(&key));
|
||||
let initial_data = [(*address.value(), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let from = Address::new(initial_data[0].0);
|
||||
let from_key = PrivateKey(1);
|
||||
let from = address;
|
||||
let from_key = key;
|
||||
let to = Address::new([2; 32]);
|
||||
let balance_to_move = 101;
|
||||
assert!(state.get_account_by_address(&from).balance < balance_to_move);
|
||||
@ -60,11 +64,15 @@ fn transition_from_authenticated_transfer_program_invocation_insuficient_balance
|
||||
|
||||
#[test]
|
||||
fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() {
|
||||
let initial_data = [([1; 32], 100), ([99; 32], 200)];
|
||||
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let address1 = Address::from_public_key(&PublicKey::new(&key1));
|
||||
let address2 = Address::from_public_key(&PublicKey::new(&key2));
|
||||
let initial_data = [(*address1.value(), 100), (*address2.value(), 200)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let from = Address::new(initial_data[1].0);
|
||||
let from_key = PrivateKey(99);
|
||||
let to = Address::new(initial_data[0].0);
|
||||
let from = address2;
|
||||
let from_key = key2;
|
||||
let to = address1;
|
||||
assert_ne!(state.get_account_by_address(&to), Account::default());
|
||||
let balance_to_move = 8;
|
||||
|
||||
@ -79,37 +87,25 @@ fn transition_from_authenticated_transfer_program_invocation_non_default_account
|
||||
|
||||
#[test]
|
||||
fn transition_from_chained_authenticated_transfer_program_invocations() {
|
||||
let initial_data = [([1; 32], 100)];
|
||||
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let address1 = Address::from_public_key(&PublicKey::new(&key1));
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let address2 = Address::from_public_key(&PublicKey::new(&key2));
|
||||
let initial_data = [(*address1.value(), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let address_1 = Address::new(initial_data[0].0);
|
||||
let key_1 = PrivateKey(1);
|
||||
let address_2 = Address::new([2; 32]);
|
||||
let key_2 = PrivateKey(2);
|
||||
let address_3 = Address::new([3; 32]);
|
||||
let address3 = Address::new([3; 32]);
|
||||
let balance_to_move = 5;
|
||||
|
||||
let tx = transfer_transaction(
|
||||
address_1.clone(),
|
||||
key_1,
|
||||
0,
|
||||
address_2.clone(),
|
||||
balance_to_move,
|
||||
);
|
||||
let tx = transfer_transaction(address1.clone(), key1, 0, address2.clone(), balance_to_move);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
let balance_to_move = 3;
|
||||
let tx = transfer_transaction(
|
||||
address_2.clone(),
|
||||
key_2,
|
||||
0,
|
||||
address_3.clone(),
|
||||
balance_to_move,
|
||||
);
|
||||
let tx = transfer_transaction(address2.clone(), key2, 0, address3.clone(), balance_to_move);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
|
||||
assert_eq!(state.get_account_by_address(&address_1).balance, 95);
|
||||
assert_eq!(state.get_account_by_address(&address_2).balance, 2);
|
||||
assert_eq!(state.get_account_by_address(&address_3).balance, 3);
|
||||
assert_eq!(state.get_account_by_address(&address_1).nonce, 1);
|
||||
assert_eq!(state.get_account_by_address(&address_2).nonce, 1);
|
||||
assert_eq!(state.get_account_by_address(&address_3).nonce, 0);
|
||||
assert_eq!(state.get_account_by_address(&address1).balance, 95);
|
||||
assert_eq!(state.get_account_by_address(&address2).balance, 2);
|
||||
assert_eq!(state.get_account_by_address(&address3).balance, 3);
|
||||
assert_eq!(state.get_account_by_address(&address1).nonce, 1);
|
||||
assert_eq!(state.get_account_by_address(&address2).nonce, 1);
|
||||
assert_eq!(state.get_account_by_address(&address3).nonce, 0);
|
||||
}
|
||||
|
||||
@ -61,7 +61,8 @@ fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_prog
|
||||
assert_eq!(account.nonce, Account::default().nonce);
|
||||
assert_eq!(account.data, Account::default().data);
|
||||
let program_id = Program::program_owner_changer().id();
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -84,7 +85,8 @@ fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_bala
|
||||
assert_eq!(account.nonce, Account::default().nonce);
|
||||
assert_eq!(account.data, Account::default().data);
|
||||
let program_id = Program::program_owner_changer().id();
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -107,7 +109,8 @@ fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonc
|
||||
assert_ne!(account.nonce, Account::default().nonce);
|
||||
assert_eq!(account.data, Account::default().data);
|
||||
let program_id = Program::program_owner_changer().id();
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -130,7 +133,8 @@ fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data
|
||||
assert_eq!(account.nonce, Account::default().nonce);
|
||||
assert_ne!(account.data, Account::default().data);
|
||||
let program_id = Program::program_owner_changer().id();
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -156,7 +160,8 @@ fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
|
||||
vec![sender_address, receiver_address],
|
||||
vec![],
|
||||
balance_to_move,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -178,7 +183,8 @@ fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
|
||||
state.get_account_by_address(&address).program_owner,
|
||||
program_id
|
||||
);
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -194,7 +200,8 @@ fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
|
||||
let address = Address::new([1; 32]);
|
||||
let program_id = Program::minter().id();
|
||||
|
||||
let message = public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
@ -219,7 +226,8 @@ fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
|
||||
assert!(state.get_account_by_address(&address).balance > balance_to_burn);
|
||||
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], balance_to_burn).unwrap();
|
||||
public_transaction::Message::try_new(program_id, vec![address], vec![], balance_to_burn)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = state.transition_from_public_transaction(&tx);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user