mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-04-12 06:03:08 +00:00
Merge 08bae6fa82d4a8249e55657bd35f388f7e25f347 into d67269e6668cc2dcc9675358e244fcdcfe813031
This commit is contained in:
commit
d986c7cd89
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -5297,7 +5297,9 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"bytesize",
|
||||
"chacha20",
|
||||
"hex",
|
||||
"k256",
|
||||
"rand 0.8.5",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -7612,6 +7614,7 @@ dependencies = [
|
||||
"borsh",
|
||||
"common",
|
||||
"nssa",
|
||||
"nssa_core",
|
||||
"rocksdb",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -35,7 +35,7 @@ pub struct BlockHeader {
|
||||
pub prev_block_hash: BlockHash,
|
||||
pub hash: BlockHash,
|
||||
pub timestamp: Timestamp,
|
||||
pub signature: nssa::Signature,
|
||||
pub signature: nssa_core::Signature,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
|
||||
@ -82,11 +82,11 @@ impl HashableBlockData {
|
||||
#[must_use]
|
||||
pub fn into_pending_block(
|
||||
self,
|
||||
signing_key: &nssa::PrivateKey,
|
||||
signing_key: &nssa_core::PrivateKey,
|
||||
bedrock_parent_id: MantleMsgId,
|
||||
) -> Block {
|
||||
let data_bytes = borsh::to_vec(&self).unwrap();
|
||||
let signature = nssa::Signature::new(signing_key, &data_bytes);
|
||||
let signature = nssa_core::Signature::new(signing_key, &data_bytes);
|
||||
let hash = OwnHasher::hash(&data_bytes);
|
||||
Block {
|
||||
header: BlockHeader {
|
||||
|
||||
@ -9,8 +9,8 @@ use crate::{
|
||||
// Helpers
|
||||
|
||||
#[must_use]
|
||||
pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey {
|
||||
nssa::PrivateKey::try_new([37; 32]).unwrap()
|
||||
pub fn sequencer_sign_key_for_testing() -> nssa_core::PrivateKey {
|
||||
nssa_core::PrivateKey::try_new([37; 32]).unwrap()
|
||||
}
|
||||
|
||||
// Dummy producers
|
||||
@ -51,7 +51,7 @@ pub fn produce_dummy_empty_transaction() -> NSSATransaction {
|
||||
instruction_data,
|
||||
)
|
||||
.unwrap();
|
||||
let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
|
||||
let private_key = nssa_core::PrivateKey::try_new([1; 32]).unwrap();
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
|
||||
|
||||
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
@ -65,7 +65,7 @@ pub fn create_transaction_native_token_transfer(
|
||||
nonce: u128,
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
signing_key: &nssa::PrivateKey,
|
||||
signing_key: &nssa_core::PrivateKey,
|
||||
) -> NSSATransaction {
|
||||
let account_ids = vec![from, to];
|
||||
let nonces = vec![nonce.into()];
|
||||
|
||||
@ -52,7 +52,7 @@ The derivation works as follows:
|
||||
|
||||
```
|
||||
seed = SHA256(owner_id || definition_id)
|
||||
ata_address = AccountId::from((ata_program_id, seed))
|
||||
ata_address = AccountId::public_account_id((ata_program_id, seed))
|
||||
```
|
||||
|
||||
Because the computation is pure, anyone who knows the owner and definition can reproduce the exact same ATA address — no network call required.
|
||||
|
||||
@ -166,7 +166,8 @@ impl IndexerStore {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nssa::{AccountId, PublicKey};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::PublicKey;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
@ -175,20 +176,20 @@ mod tests {
|
||||
common::test_utils::produce_dummy_block(1, None, vec![])
|
||||
}
|
||||
|
||||
fn acc1_sign_key() -> nssa::PrivateKey {
|
||||
nssa::PrivateKey::try_new([1; 32]).unwrap()
|
||||
fn acc1_sign_key() -> nssa_core::PrivateKey {
|
||||
nssa_core::PrivateKey::try_new([1; 32]).unwrap()
|
||||
}
|
||||
|
||||
fn acc2_sign_key() -> nssa::PrivateKey {
|
||||
nssa::PrivateKey::try_new([2; 32]).unwrap()
|
||||
fn acc2_sign_key() -> nssa_core::PrivateKey {
|
||||
nssa_core::PrivateKey::try_new([2; 32]).unwrap()
|
||||
}
|
||||
|
||||
fn acc1() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(&acc1_sign_key()))
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(&acc1_sign_key()))
|
||||
}
|
||||
|
||||
fn acc2() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(&acc2_sign_key()))
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(&acc2_sign_key()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -11,7 +11,8 @@ use logos_blockchain_core::mantle::{
|
||||
Op, SignedMantleTx,
|
||||
ops::channel::{ChannelId, inscribe::InscriptionOp},
|
||||
};
|
||||
use nssa::V03State;
|
||||
use nssa::{AccountId, V03State};
|
||||
use nssa_core::account::Identifier;
|
||||
use testnet_initial_state::initial_state_testnet;
|
||||
|
||||
use crate::{block_store::IndexerStore, config::IndexerConfig};
|
||||
@ -53,7 +54,7 @@ impl IndexerCore {
|
||||
// because it will be overwritten by sequencer.
|
||||
// Therefore:
|
||||
// ToDo: remove key from indexer config, use some default.
|
||||
let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap();
|
||||
let signing_key = nssa_core::PrivateKey::try_new(config.signing_key).unwrap();
|
||||
let channel_genesis_msg_id = [0; 32];
|
||||
let genesis_block = hashable_data.into_pending_block(&signing_key, channel_genesis_msg_id);
|
||||
|
||||
@ -71,7 +72,10 @@ impl IndexerCore {
|
||||
acc.program_owner =
|
||||
nssa::program::Program::authenticated_transfer_program().id();
|
||||
|
||||
nssa_core::Commitment::new(npk, &acc)
|
||||
nssa_core::Commitment::new(
|
||||
&AccountId::private_account_id(npk, Identifier(0_u128)),
|
||||
&acc,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
@ -165,28 +165,28 @@ impl From<EphemeralPublicKey> for nssa_core::encryption::EphemeralPublicKey {
|
||||
// Signature and PublicKey conversions
|
||||
// ============================================================================
|
||||
|
||||
impl From<nssa::Signature> for Signature {
|
||||
fn from(value: nssa::Signature) -> Self {
|
||||
let nssa::Signature { value } = value;
|
||||
impl From<nssa_core::Signature> for Signature {
|
||||
fn from(value: nssa_core::Signature) -> Self {
|
||||
let nssa_core::Signature { value } = value;
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signature> for nssa::Signature {
|
||||
impl From<Signature> for nssa_core::Signature {
|
||||
fn from(value: Signature) -> Self {
|
||||
let Signature(sig_value) = value;
|
||||
Self { value: sig_value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nssa::PublicKey> for PublicKey {
|
||||
fn from(value: nssa::PublicKey) -> Self {
|
||||
impl From<nssa_core::PublicKey> for PublicKey {
|
||||
fn from(value: nssa_core::PublicKey) -> Self {
|
||||
Self(*value.value())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PublicKey> for nssa::PublicKey {
|
||||
type Error = nssa::error::NssaError;
|
||||
impl TryFrom<PublicKey> for nssa_core::PublicKey {
|
||||
type Error = nssa_core::error::NssaCoreError;
|
||||
|
||||
fn try_from(value: PublicKey) -> Result<Self, Self::Error> {
|
||||
Self::try_new(value.0)
|
||||
|
||||
@ -3,9 +3,13 @@ use std::{net::SocketAddr, path::PathBuf, time::Duration};
|
||||
use anyhow::{Context as _, Result};
|
||||
use bytesize::ByteSize;
|
||||
use indexer_service::{BackoffConfig, ChannelId, ClientConfig, IndexerConfig};
|
||||
use key_protocol::key_management::KeyChain;
|
||||
use nssa::{Account, AccountId, PrivateKey, PublicKey};
|
||||
use nssa_core::{account::Data, program::DEFAULT_PROGRAM_ID};
|
||||
use key_protocol::{key_management::KeyChain, key_protocol_core::PrivateBundle};
|
||||
use nssa::{Account, AccountId};
|
||||
use nssa_core::{
|
||||
PrivateKey, PublicKey,
|
||||
account::{Data, Identifier},
|
||||
program::DEFAULT_PROGRAM_ID,
|
||||
};
|
||||
use sequencer_core::config::{BedrockConfig, SequencerConfig};
|
||||
use testnet_initial_state::{
|
||||
PrivateAccountPrivateInitialData, PrivateAccountPublicInitialData,
|
||||
@ -36,7 +40,7 @@ impl Default for SequencerPartialConfig {
|
||||
|
||||
pub struct InitialData {
|
||||
pub public_accounts: Vec<(PrivateKey, u128)>,
|
||||
pub private_accounts: Vec<(KeyChain, Account)>,
|
||||
pub private_accounts: Vec<PrivateBundle>,
|
||||
}
|
||||
|
||||
impl InitialData {
|
||||
@ -45,11 +49,11 @@ impl InitialData {
|
||||
let mut public_alice_private_key = PrivateKey::new_os_random();
|
||||
let mut public_alice_public_key =
|
||||
PublicKey::new_from_private_key(&public_alice_private_key);
|
||||
let mut public_alice_account_id = AccountId::from(&public_alice_public_key);
|
||||
let mut public_alice_account_id = AccountId::public_account_id(&public_alice_public_key);
|
||||
|
||||
let mut public_bob_private_key = PrivateKey::new_os_random();
|
||||
let mut public_bob_public_key = PublicKey::new_from_private_key(&public_bob_private_key);
|
||||
let mut public_bob_account_id = AccountId::from(&public_bob_public_key);
|
||||
let mut public_bob_account_id = AccountId::public_account_id(&public_bob_public_key);
|
||||
|
||||
// Ensure consistent ordering
|
||||
if public_alice_account_id > public_bob_account_id {
|
||||
@ -59,12 +63,18 @@ impl InitialData {
|
||||
}
|
||||
|
||||
let mut private_charlie_key_chain = KeyChain::new_os_random();
|
||||
let mut private_charlie_account_id =
|
||||
AccountId::from(&private_charlie_key_chain.nullifier_public_key);
|
||||
let mut private_charlie_identifier = Identifier::new_os_random();
|
||||
let mut private_charlie_account_id = AccountId::private_account_id(
|
||||
&private_charlie_key_chain.nullifier_public_key,
|
||||
private_charlie_identifier,
|
||||
);
|
||||
|
||||
let mut private_david_key_chain = KeyChain::new_os_random();
|
||||
let mut private_david_account_id =
|
||||
AccountId::from(&private_david_key_chain.nullifier_public_key);
|
||||
let mut private_david_identifier = Identifier::new_os_random();
|
||||
let mut private_david_account_id = AccountId::private_account_id(
|
||||
&private_david_key_chain.nullifier_public_key,
|
||||
private_david_identifier,
|
||||
);
|
||||
|
||||
// Ensure consistent ordering
|
||||
if private_charlie_account_id > private_david_account_id {
|
||||
@ -73,6 +83,10 @@ impl InitialData {
|
||||
&mut private_charlie_account_id,
|
||||
&mut private_david_account_id,
|
||||
);
|
||||
std::mem::swap(
|
||||
&mut private_charlie_identifier,
|
||||
&mut private_david_identifier,
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
@ -81,24 +95,26 @@ impl InitialData {
|
||||
(public_bob_private_key, 20_000),
|
||||
],
|
||||
private_accounts: vec![
|
||||
(
|
||||
private_charlie_key_chain,
|
||||
Account {
|
||||
PrivateBundle {
|
||||
key_chain: private_charlie_key_chain,
|
||||
identifier: private_charlie_identifier,
|
||||
account: Account {
|
||||
balance: 10_000,
|
||||
data: Data::default(),
|
||||
program_owner: DEFAULT_PROGRAM_ID,
|
||||
nonce: 0_u128.into(),
|
||||
},
|
||||
),
|
||||
(
|
||||
private_david_key_chain,
|
||||
Account {
|
||||
},
|
||||
PrivateBundle {
|
||||
key_chain: private_david_key_chain,
|
||||
identifier: private_david_identifier,
|
||||
account: Account {
|
||||
balance: 20_000,
|
||||
data: Data::default(),
|
||||
program_owner: DEFAULT_PROGRAM_ID,
|
||||
nonce: 0_u128.into(),
|
||||
},
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
@ -108,7 +124,7 @@ impl InitialData {
|
||||
.iter()
|
||||
.map(|(priv_key, balance)| {
|
||||
let pub_key = PublicKey::new_from_private_key(priv_key);
|
||||
let account_id = AccountId::from(&pub_key);
|
||||
let account_id = AccountId::public_account_id(&pub_key);
|
||||
PublicAccountPublicInitialData {
|
||||
account_id,
|
||||
balance: *balance,
|
||||
@ -120,9 +136,10 @@ impl InitialData {
|
||||
fn sequencer_initial_private_accounts(&self) -> Vec<PrivateAccountPublicInitialData> {
|
||||
self.private_accounts
|
||||
.iter()
|
||||
.map(|(key_chain, account)| PrivateAccountPublicInitialData {
|
||||
npk: key_chain.nullifier_public_key.clone(),
|
||||
account: account.clone(),
|
||||
.map(|bundle| PrivateAccountPublicInitialData {
|
||||
npk: bundle.key_chain.nullifier_public_key.clone(),
|
||||
identifier: bundle.identifier,
|
||||
account: bundle.account.clone(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -132,18 +149,22 @@ impl InitialData {
|
||||
.iter()
|
||||
.map(|(priv_key, _)| {
|
||||
let pub_key = PublicKey::new_from_private_key(priv_key);
|
||||
let account_id = AccountId::from(&pub_key);
|
||||
let account_id = AccountId::public_account_id(&pub_key);
|
||||
InitialAccountData::Public(PublicAccountPrivateInitialData {
|
||||
account_id,
|
||||
pub_sign_key: priv_key.clone(),
|
||||
})
|
||||
})
|
||||
.chain(self.private_accounts.iter().map(|(key_chain, account)| {
|
||||
let account_id = AccountId::from(&key_chain.nullifier_public_key);
|
||||
.chain(self.private_accounts.iter().map(|bundle| {
|
||||
let account_id = AccountId::private_account_id(
|
||||
&bundle.key_chain.nullifier_public_key,
|
||||
bundle.identifier,
|
||||
);
|
||||
InitialAccountData::Private(Box::new(PrivateAccountPrivateInitialData {
|
||||
account_id,
|
||||
account: account.clone(),
|
||||
key_chain: key_chain.clone(),
|
||||
account: bundle.account.clone(),
|
||||
identifier: bundle.identifier,
|
||||
key_chain: bundle.key_chain.clone(),
|
||||
}))
|
||||
}))
|
||||
.collect()
|
||||
|
||||
@ -49,7 +49,6 @@ async fn private_transfer_to_owned_account() -> Result<()> {
|
||||
.get_private_account_commitment(to)
|
||||
.context("Failed to get private account commitment for receiver")?;
|
||||
assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await);
|
||||
|
||||
info!("Successfully transferred privately to owned account");
|
||||
|
||||
Ok(())
|
||||
@ -75,26 +74,24 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
|
||||
});
|
||||
|
||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = result else {
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } = result else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment1 = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(from)
|
||||
.context("Failed to get private account commitment for sender")?;
|
||||
|
||||
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
||||
assert_eq!(tx.message.new_commitments[0], new_commitment1);
|
||||
|
||||
assert_eq!(tx.message.new_commitments.len(), 2);
|
||||
for commitment in tx.message.new_commitments {
|
||||
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
||||
}
|
||||
|
||||
// info!("Waiting for next block creation");
|
||||
// tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
//
|
||||
// let new_commitment1 = ctx
|
||||
// .wallet()
|
||||
// .get_private_account_commitment(from)
|
||||
// .context("Failed to get private account commitment for sender")?;
|
||||
//
|
||||
// let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
||||
// assert_eq!(tx.message.new_commitments[0], new_commitment1);
|
||||
//
|
||||
// assert_eq!(tx.message.new_commitments.len(), 2);
|
||||
// for commitment in tx.message.new_commitments {
|
||||
// assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
|
||||
// }
|
||||
info!("Successfully transferred privately to foreign account");
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -259,16 +259,16 @@ async fn restore_keys_from_seed() -> Result<()> {
|
||||
.expect("Acc 4 should be restored");
|
||||
|
||||
assert_eq!(
|
||||
acc1.value.1.program_owner,
|
||||
acc1.value.account.program_owner,
|
||||
Program::authenticated_transfer_program().id()
|
||||
);
|
||||
assert_eq!(
|
||||
acc2.value.1.program_owner,
|
||||
acc2.value.account.program_owner,
|
||||
Program::authenticated_transfer_program().id()
|
||||
);
|
||||
|
||||
assert_eq!(acc1.value.1.balance, 100);
|
||||
assert_eq!(acc2.value.1.balance, 101);
|
||||
assert_eq!(acc1.value.account.balance, 100);
|
||||
assert_eq!(acc2.value.account.balance, 101);
|
||||
|
||||
info!("Tree checks passed, testing restored accounts can transact");
|
||||
|
||||
|
||||
@ -18,17 +18,20 @@ use integration_tests::{
|
||||
TestContext,
|
||||
config::{InitialData, SequencerPartialConfig},
|
||||
};
|
||||
use key_protocol::key_management::{KeyChain, ephemeral_key_holder::EphemeralKeyHolder};
|
||||
use key_protocol::{
|
||||
key_management::{KeyChain, ephemeral_key_holder::EphemeralKeyHolder},
|
||||
key_protocol_core::PrivateBundle,
|
||||
};
|
||||
use log::info;
|
||||
use nssa::{
|
||||
Account, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, PublicTransaction,
|
||||
Account, AccountId, PrivacyPreservingTransaction, PublicTransaction,
|
||||
privacy_preserving_transaction::{self as pptx, circuit},
|
||||
program::Program,
|
||||
public_transaction as putx,
|
||||
};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey,
|
||||
account::{AccountWithMetadata, Nonce, data::Data},
|
||||
MembershipProof, NullifierPublicKey, PrivateKey, PublicKey,
|
||||
account::{AccountWithMetadata, Identifier, Nonce, data::Data},
|
||||
encryption::ViewingPublicKey,
|
||||
};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
@ -49,7 +52,7 @@ impl TpsTestManager {
|
||||
private_key_bytes[..8].copy_from_slice(&i.to_le_bytes());
|
||||
let private_key = PrivateKey::try_new(private_key_bytes).unwrap();
|
||||
let public_key = PublicKey::new_from_private_key(&private_key);
|
||||
let account_id = AccountId::from(&public_key);
|
||||
let account_id = AccountId::public_account_id(&public_key);
|
||||
(private_key, account_id)
|
||||
})
|
||||
.collect();
|
||||
@ -107,6 +110,7 @@ impl TpsTestManager {
|
||||
// Generate an initial commitment to be used with the privacy preserving transaction
|
||||
// created with the `build_privacy_transaction` function.
|
||||
let key_chain = KeyChain::new_os_random();
|
||||
let identifier = Identifier::new_os_random();
|
||||
let account = Account {
|
||||
balance: 100,
|
||||
nonce: Nonce(0xdead_beef),
|
||||
@ -116,7 +120,11 @@ impl TpsTestManager {
|
||||
|
||||
InitialData {
|
||||
public_accounts,
|
||||
private_accounts: vec![(key_chain, account)],
|
||||
private_accounts: vec![PrivateBundle {
|
||||
key_chain,
|
||||
identifier,
|
||||
account,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,6 +220,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
|
||||
let sender_vsk = [99; 32];
|
||||
let sender_vpk = ViewingPublicKey::from_scalar(sender_vsk);
|
||||
let sender_npk = NullifierPublicKey::from(&sender_nsk);
|
||||
let sender_id = AccountId::private_account_id(&sender_npk, Identifier(0_u128));
|
||||
let sender_pre = AccountWithMetadata::new(
|
||||
Account {
|
||||
balance: 100,
|
||||
@ -220,14 +229,18 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
|
||||
data: Data::default(),
|
||||
},
|
||||
true,
|
||||
AccountId::from(&sender_npk),
|
||||
AccountId::private_account_id(&sender_npk, Identifier(0_u128)),
|
||||
);
|
||||
let recipient_nsk = [2; 32];
|
||||
let recipient_vsk = [99; 32];
|
||||
let recipient_vpk = ViewingPublicKey::from_scalar(recipient_vsk);
|
||||
let recipient_npk = NullifierPublicKey::from(&recipient_nsk);
|
||||
let recipient_pre =
|
||||
AccountWithMetadata::new(Account::default(), false, AccountId::from(&recipient_npk));
|
||||
let recipient_id = AccountId::private_account_id(&recipient_npk, Identifier(0_u128));
|
||||
let recipient_pre = AccountWithMetadata::new(
|
||||
Account::default(),
|
||||
false,
|
||||
AccountId::private_account_id(&recipient_npk, Identifier(0_u128)),
|
||||
);
|
||||
|
||||
let eph_holder_from = EphemeralKeyHolder::new(&sender_npk);
|
||||
let sender_ss = eph_holder_from.calculate_shared_secret_sender(&sender_vpk);
|
||||
@ -249,11 +262,9 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
|
||||
vec![sender_pre, recipient_pre],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![
|
||||
(sender_npk.clone(), sender_ss),
|
||||
(recipient_npk.clone(), recipient_ss),
|
||||
],
|
||||
vec![(sender_npk, sender_ss), (recipient_npk, recipient_ss)],
|
||||
vec![sender_nsk],
|
||||
vec![],
|
||||
vec![Some(proof)],
|
||||
&program.into(),
|
||||
)
|
||||
@ -262,8 +273,8 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
|
||||
vec![],
|
||||
vec![],
|
||||
vec![
|
||||
(sender_npk, sender_vpk, sender_epk),
|
||||
(recipient_npk, recipient_vpk, recipient_epk),
|
||||
(sender_id, sender_vpk, sender_epk),
|
||||
(recipient_id, recipient_vpk, recipient_epk),
|
||||
],
|
||||
output,
|
||||
)
|
||||
|
||||
@ -21,8 +21,8 @@ use std::{
|
||||
use anyhow::Result;
|
||||
use integration_tests::{BlockingTestContext, TIME_TO_WAIT_FOR_BLOCK_SECONDS};
|
||||
use log::info;
|
||||
use nssa::{Account, AccountId, PrivateKey, PublicKey, program::Program};
|
||||
use nssa_core::program::DEFAULT_PROGRAM_ID;
|
||||
use nssa::{Account, AccountId, program::Program};
|
||||
use nssa_core::{PrivateKey, PublicKey, account::Identifier, program::DEFAULT_PROGRAM_ID};
|
||||
use tempfile::tempdir;
|
||||
use wallet_ffi::{
|
||||
FfiAccount, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey,
|
||||
@ -332,7 +332,7 @@ fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
nssa::AccountId::from(&private_account_keys.npk()),
|
||||
nssa::AccountId::private_account_id(&private_account_keys.npk(), Identifier(0_u128)),
|
||||
out_private_account_id.into()
|
||||
);
|
||||
|
||||
@ -607,7 +607,7 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
|
||||
fn test_wallet_ffi_account_id_to_base58() -> Result<()> {
|
||||
let private_key = PrivateKey::new_os_random();
|
||||
let public_key = PublicKey::new_from_private_key(&private_key);
|
||||
let account_id = AccountId::from(&public_key);
|
||||
let account_id = AccountId::public_account_id(&public_key);
|
||||
let ffi_bytes: FfiBytes32 = (&account_id).into();
|
||||
let ptr = unsafe { wallet_ffi_account_id_to_base58(&raw const ffi_bytes) };
|
||||
|
||||
@ -626,7 +626,7 @@ fn test_wallet_ffi_account_id_to_base58() -> Result<()> {
|
||||
fn wallet_ffi_base58_to_account_id() -> Result<()> {
|
||||
let private_key = PrivateKey::new_os_random();
|
||||
let public_key = PublicKey::new_from_private_key(&private_key);
|
||||
let account_id = AccountId::from(&public_key);
|
||||
let account_id = AccountId::public_account_id(&public_key);
|
||||
let account_id_str = account_id.to_string();
|
||||
let account_id_c_str = CString::new(account_id_str.clone())?;
|
||||
let account_id: AccountId = unsafe {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use k256::{Scalar, elliptic_curve::PrimeField as _};
|
||||
use nssa_core::{NullifierPublicKey, encryption::ViewingPublicKey};
|
||||
use nssa_core::{NullifierPublicKey, account::Identifier, encryption::ViewingPublicKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -13,7 +13,7 @@ use crate::{
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ChildKeysPrivate {
|
||||
pub value: (KeyChain, nssa::Account),
|
||||
pub value: PrivateBundle,
|
||||
pub ccc: [u8; 32],
|
||||
/// Can be [`None`] if root.
|
||||
pub cci: Option<u32>,
|
||||
@ -39,8 +39,8 @@ impl KeyNode for ChildKeysPrivate {
|
||||
let vpk = ViewingPublicKey::from_scalar(vsk);
|
||||
|
||||
Self {
|
||||
value: (
|
||||
KeyChain {
|
||||
value: PrivateBundle {
|
||||
key_chain: KeyChain {
|
||||
secret_spending_key: ssk,
|
||||
nullifier_public_key: npk,
|
||||
viewing_public_key: vpk,
|
||||
@ -49,8 +49,9 @@ impl KeyNode for ChildKeysPrivate {
|
||||
viewing_secret_key: vsk,
|
||||
},
|
||||
},
|
||||
nssa::Account::default(),
|
||||
),
|
||||
identifier: Identifier::default(),
|
||||
account: nssa::Account::default(),
|
||||
},
|
||||
ccc,
|
||||
cci: None,
|
||||
}
|
||||
@ -58,11 +59,22 @@ impl KeyNode for ChildKeysPrivate {
|
||||
|
||||
fn nth_child(&self, cci: u32) -> Self {
|
||||
#[expect(clippy::arithmetic_side_effects, reason = "TODO: fix later")]
|
||||
let parent_pt =
|
||||
Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into())
|
||||
.expect("Key generated as scalar, must be valid representation")
|
||||
* Scalar::from_repr(self.value.0.private_key_holder.viewing_secret_key.into())
|
||||
.expect("Key generated as scalar, must be valid representation");
|
||||
let parent_pt = Scalar::from_repr(
|
||||
self.value
|
||||
.key_chain
|
||||
.private_key_holder
|
||||
.nullifier_secret_key
|
||||
.into(),
|
||||
)
|
||||
.expect("Key generated as scalar, must be valid representation")
|
||||
* Scalar::from_repr(
|
||||
self.value
|
||||
.key_chain
|
||||
.private_key_holder
|
||||
.viewing_secret_key
|
||||
.into(),
|
||||
)
|
||||
.expect("Key generated as scalar, must be valid representation");
|
||||
let mut input = vec![];
|
||||
|
||||
input.extend_from_slice(b"LEE_seed_priv");
|
||||
@ -88,8 +100,8 @@ impl KeyNode for ChildKeysPrivate {
|
||||
let vpk = ViewingPublicKey::from_scalar(vsk);
|
||||
|
||||
Self {
|
||||
value: (
|
||||
KeyChain {
|
||||
value: PrivateBundle {
|
||||
key_chain: KeyChain {
|
||||
secret_spending_key: ssk,
|
||||
nullifier_public_key: npk,
|
||||
viewing_public_key: vpk,
|
||||
@ -98,8 +110,9 @@ impl KeyNode for ChildKeysPrivate {
|
||||
viewing_secret_key: vsk,
|
||||
},
|
||||
},
|
||||
nssa::Account::default(),
|
||||
),
|
||||
identifier: Identifier(0_u128), // TODO: this Marvin
|
||||
account: nssa::Account::default(),
|
||||
},
|
||||
ccc,
|
||||
cci: Some(cci),
|
||||
}
|
||||
@ -114,17 +127,10 @@ impl KeyNode for ChildKeysPrivate {
|
||||
}
|
||||
|
||||
fn account_id(&self) -> nssa::AccountId {
|
||||
nssa::AccountId::from(&self.value.0.nullifier_public_key)
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::single_char_lifetime_names,
|
||||
reason = "TODO add meaningful name"
|
||||
)]
|
||||
impl<'a> From<&'a ChildKeysPrivate> for &'a (KeyChain, nssa::Account) {
|
||||
fn from(value: &'a ChildKeysPrivate) -> Self {
|
||||
&value.value
|
||||
nssa::AccountId::private_account_id(
|
||||
&self.value.key_chain.nullifier_public_key,
|
||||
Identifier(0_u128),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,10 +140,7 @@ impl<'a> From<&'a ChildKeysPrivate> for &'a (KeyChain, nssa::Account) {
|
||||
)]
|
||||
impl<'a> From<&'a mut ChildKeysPrivate> for PrivateBundle {
|
||||
fn from(value: &'a mut ChildKeysPrivate) -> Self {
|
||||
Self {
|
||||
key_chain: value.value.0.clone(),
|
||||
account: value.value.1.clone(),
|
||||
}
|
||||
value.value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,12 +192,12 @@ mod tests {
|
||||
80, 170, 66, 217, 79, 38, 80, 11, 74, 147, 123, 221, 159, 166,
|
||||
];
|
||||
|
||||
assert!(expected_ssk == keys.value.0.secret_spending_key);
|
||||
assert!(expected_ssk == keys.value.key_chain.secret_spending_key);
|
||||
assert!(expected_ccc == keys.ccc);
|
||||
assert!(expected_nsk == keys.value.0.private_key_holder.nullifier_secret_key);
|
||||
assert!(expected_npk == keys.value.0.nullifier_public_key);
|
||||
assert!(expected_vsk == keys.value.0.private_key_holder.viewing_secret_key);
|
||||
assert!(expected_vpk_as_bytes == keys.value.0.viewing_public_key.to_bytes());
|
||||
assert!(expected_nsk == keys.value.key_chain.private_key_holder.nullifier_secret_key);
|
||||
assert!(expected_npk == keys.value.key_chain.nullifier_public_key);
|
||||
assert!(expected_vsk == keys.value.key_chain.private_key_holder.viewing_secret_key);
|
||||
assert!(expected_vpk_as_bytes == keys.value.key_chain.viewing_public_key.to_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -233,9 +236,23 @@ mod tests {
|
||||
];
|
||||
|
||||
assert!(expected_ccc == child_node.ccc);
|
||||
assert!(expected_nsk == child_node.value.0.private_key_holder.nullifier_secret_key);
|
||||
assert!(expected_npk == child_node.value.0.nullifier_public_key);
|
||||
assert!(expected_vsk == child_node.value.0.private_key_holder.viewing_secret_key);
|
||||
assert!(expected_vpk_as_bytes == child_node.value.0.viewing_public_key.to_bytes());
|
||||
assert!(
|
||||
expected_nsk
|
||||
== child_node
|
||||
.value
|
||||
.key_chain
|
||||
.private_key_holder
|
||||
.nullifier_secret_key
|
||||
);
|
||||
assert!(expected_npk == child_node.value.key_chain.nullifier_public_key);
|
||||
assert!(
|
||||
expected_vsk
|
||||
== child_node
|
||||
.value
|
||||
.key_chain
|
||||
.private_key_holder
|
||||
.viewing_secret_key
|
||||
);
|
||||
assert!(expected_vpk_as_bytes == child_node.value.key_chain.viewing_public_key.to_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@ use crate::key_management::key_tree::traits::KeyNode;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ChildKeysPublic {
|
||||
pub csk: nssa::PrivateKey,
|
||||
pub cpk: nssa::PublicKey,
|
||||
pub csk: nssa_core::PrivateKey,
|
||||
pub cpk: nssa_core::PublicKey,
|
||||
pub ccc: [u8; 32],
|
||||
/// Can be [`None`] if root.
|
||||
pub cci: Option<u32>,
|
||||
@ -41,14 +41,14 @@ impl KeyNode for ChildKeysPublic {
|
||||
fn root(seed: [u8; 64]) -> Self {
|
||||
let hash_value = hmac_sha512::HMAC::mac(seed, "LEE_master_pub");
|
||||
|
||||
let csk = nssa::PrivateKey::try_new(
|
||||
let csk = nssa_core::PrivateKey::try_new(
|
||||
*hash_value
|
||||
.first_chunk::<32>()
|
||||
.expect("hash_value is 64 bytes, must be safe to get first 32"),
|
||||
)
|
||||
.expect("Expect a valid Private Key");
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
let cpk = nssa_core::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
@ -61,7 +61,7 @@ impl KeyNode for ChildKeysPublic {
|
||||
fn nth_child(&self, cci: u32) -> Self {
|
||||
let hash_value = self.compute_hash_value(cci);
|
||||
|
||||
let csk = nssa::PrivateKey::try_new({
|
||||
let csk = nssa_core::PrivateKey::try_new({
|
||||
let hash_value = hash_value
|
||||
.first_chunk::<32>()
|
||||
.expect("hash_value is 64 bytes, must be safe to get first 32");
|
||||
@ -80,7 +80,7 @@ impl KeyNode for ChildKeysPublic {
|
||||
.last_chunk::<32>()
|
||||
.expect("hash_value is 64 bytes, must be safe to get last 32");
|
||||
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
let cpk = nssa_core::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
@ -99,7 +99,7 @@ impl KeyNode for ChildKeysPublic {
|
||||
}
|
||||
|
||||
fn account_id(&self) -> nssa::AccountId {
|
||||
nssa::AccountId::from(&self.cpk)
|
||||
nssa::AccountId::public_account_id(&self.cpk)
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ impl KeyNode for ChildKeysPublic {
|
||||
clippy::single_char_lifetime_names,
|
||||
reason = "TODO add meaningful name"
|
||||
)]
|
||||
impl<'a> From<&'a ChildKeysPublic> for &'a nssa::PrivateKey {
|
||||
impl<'a> From<&'a ChildKeysPublic> for &'a nssa_core::PrivateKey {
|
||||
fn from(value: &'a ChildKeysPublic) -> Self {
|
||||
&value.csk
|
||||
}
|
||||
@ -115,7 +115,7 @@ impl<'a> From<&'a ChildKeysPublic> for &'a nssa::PrivateKey {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nssa::{PrivateKey, PublicKey};
|
||||
use nssa_core::{PrivateKey, PublicKey};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@ -212,7 +212,7 @@ impl KeyTree<ChildKeysPrivate> {
|
||||
println!("Cleanup of tree at depth {i}");
|
||||
for id in ChainIndex::chain_ids_at_depth(i) {
|
||||
if let Some(node) = self.key_map.get(&id) {
|
||||
if node.value.1 == nssa::Account::default() {
|
||||
if node.value.account == nssa::Account::default() {
|
||||
let addr = node.account_id();
|
||||
self.remove(addr);
|
||||
} else {
|
||||
@ -478,25 +478,25 @@ mod tests {
|
||||
.key_map
|
||||
.get_mut(&ChainIndex::from_str("/1").unwrap())
|
||||
.unwrap();
|
||||
acc.value.1.balance = 2;
|
||||
acc.value.account.balance = 2;
|
||||
|
||||
let acc = tree
|
||||
.key_map
|
||||
.get_mut(&ChainIndex::from_str("/2").unwrap())
|
||||
.unwrap();
|
||||
acc.value.1.balance = 3;
|
||||
acc.value.account.balance = 3;
|
||||
|
||||
let acc = tree
|
||||
.key_map
|
||||
.get_mut(&ChainIndex::from_str("/0/1").unwrap())
|
||||
.unwrap();
|
||||
acc.value.1.balance = 5;
|
||||
acc.value.account.balance = 5;
|
||||
|
||||
let acc = tree
|
||||
.key_map
|
||||
.get_mut(&ChainIndex::from_str("/1/0").unwrap())
|
||||
.unwrap();
|
||||
acc.value.1.balance = 6;
|
||||
acc.value.account.balance = 6;
|
||||
|
||||
tree.cleanup_tree_remove_uninit_layered(10);
|
||||
|
||||
@ -518,15 +518,15 @@ mod tests {
|
||||
assert_eq!(key_set, key_set_res);
|
||||
|
||||
let acc = &tree.key_map[&ChainIndex::from_str("/1").unwrap()];
|
||||
assert_eq!(acc.value.1.balance, 2);
|
||||
assert_eq!(acc.value.account.balance, 2);
|
||||
|
||||
let acc = &tree.key_map[&ChainIndex::from_str("/2").unwrap()];
|
||||
assert_eq!(acc.value.1.balance, 3);
|
||||
assert_eq!(acc.value.account.balance, 3);
|
||||
|
||||
let acc = &tree.key_map[&ChainIndex::from_str("/0/1").unwrap()];
|
||||
assert_eq!(acc.value.1.balance, 5);
|
||||
assert_eq!(acc.value.account.balance, 5);
|
||||
|
||||
let acc = &tree.key_map[&ChainIndex::from_str("/1/0").unwrap()];
|
||||
assert_eq!(acc.value.1.balance, 6);
|
||||
assert_eq!(acc.value.account.balance, 6);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,11 +125,11 @@ mod tests {
|
||||
let nullifier_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
|
||||
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
||||
|
||||
let pub_account_signing_key = nssa::PrivateKey::new_os_random();
|
||||
let pub_account_signing_key = nssa_core::PrivateKey::new_os_random();
|
||||
|
||||
let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key);
|
||||
let public_key = nssa_core::PublicKey::new_from_private_key(&pub_account_signing_key);
|
||||
|
||||
let account = nssa::AccountId::from(&public_key);
|
||||
let account = nssa::AccountId::public_account_id(&public_key);
|
||||
|
||||
println!("======Prerequisites======");
|
||||
println!();
|
||||
@ -178,7 +178,7 @@ mod tests {
|
||||
.get_node(second_child_id)
|
||||
.unwrap()
|
||||
.value
|
||||
.0
|
||||
.key_chain
|
||||
.clone()
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use k256::AffinePoint;
|
||||
use nssa_core::account::Identifier;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::{
|
||||
@ -27,12 +28,13 @@ pub struct NSSAUserData {
|
||||
/// TODO: eventually, this should have `sign_key: Option<PrivateKey>` and `pub_key: PublicKey`.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PublicBundle {
|
||||
pub sign_key: nssa::PrivateKey,
|
||||
pub sign_key: nssa_core::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PrivateBundle {
|
||||
pub key_chain: KeyChain,
|
||||
pub identifier: Identifier,
|
||||
pub account: nssa_core::account::Account,
|
||||
}
|
||||
|
||||
@ -42,8 +44,8 @@ impl NSSAUserData {
|
||||
) -> bool {
|
||||
let mut check_res = true;
|
||||
for (account_id, public_bundle) in accounts_keys_map {
|
||||
let expected_account_id = nssa::AccountId::from(
|
||||
&nssa::PublicKey::new_from_private_key(&public_bundle.sign_key),
|
||||
let expected_account_id = nssa::AccountId::public_account_id(
|
||||
&nssa_core::PublicKey::new_from_private_key(&public_bundle.sign_key),
|
||||
);
|
||||
if &expected_account_id != account_id {
|
||||
println!("{expected_account_id}, {account_id}");
|
||||
@ -58,7 +60,10 @@ impl NSSAUserData {
|
||||
) -> bool {
|
||||
let mut check_res = true;
|
||||
for (account_id, bundle) in accounts_keys_map {
|
||||
let expected_account_id = nssa::AccountId::from(&bundle.key_chain.nullifier_public_key);
|
||||
let expected_account_id = nssa::AccountId::private_account_id(
|
||||
&bundle.key_chain.nullifier_public_key,
|
||||
bundle.identifier,
|
||||
);
|
||||
if expected_account_id != *account_id {
|
||||
println!("{expected_account_id}, {account_id}");
|
||||
check_res = false;
|
||||
@ -117,7 +122,7 @@ impl NSSAUserData {
|
||||
pub fn get_pub_account_signing_key(
|
||||
&self,
|
||||
account_id: nssa::AccountId,
|
||||
) -> Option<&nssa::PrivateKey> {
|
||||
) -> Option<&nssa_core::PrivateKey> {
|
||||
self.default_pub_account_signing_keys
|
||||
.get(&account_id)
|
||||
.map(|bundle| &bundle.sign_key)
|
||||
@ -153,8 +158,9 @@ impl NSSAUserData {
|
||||
self.private_key_tree
|
||||
.get_node(account_id)
|
||||
.map(|child_keys_private| PrivateBundle {
|
||||
key_chain: child_keys_private.value.0.clone(),
|
||||
account: child_keys_private.value.1.clone(),
|
||||
key_chain: child_keys_private.value.key_chain.clone(),
|
||||
identifier: child_keys_private.value.identifier,
|
||||
account: child_keys_private.value.account.clone(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ license = { workspace = true }
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { workspace = true, features = ["host"] }
|
||||
nssa_core = { workspace = true, features = ["host", "test-utils"] }
|
||||
clock_core.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
|
||||
@ -12,10 +12,12 @@ risc0-zkvm.workspace = true
|
||||
borsh.workspace = true
|
||||
serde.workspace = true
|
||||
serde_with.workspace = true
|
||||
rand.workspace = true
|
||||
thiserror.workspace = true
|
||||
bytemuck.workspace = true
|
||||
bytesize.workspace = true
|
||||
base58.workspace = true
|
||||
hex.workspace = true
|
||||
k256 = { workspace = true, optional = true }
|
||||
chacha20 = { version = "0.10" }
|
||||
|
||||
@ -23,5 +25,6 @@ chacha20 = { version = "0.10" }
|
||||
serde_json.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["dep:k256"]
|
||||
host = ["dep:k256"]
|
||||
test-utils = ["dep:k256"]
|
||||
|
||||
@ -6,16 +6,21 @@ use std::{
|
||||
use base58::{FromBase58 as _, ToBase58 as _};
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
pub use data::Data;
|
||||
use rand::{RngCore as _, rngs::OsRng};
|
||||
use risc0_zkvm::sha::{Impl, Sha256 as _};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||
|
||||
use crate::{NullifierPublicKey, NullifierSecretKey, program::ProgramId};
|
||||
use crate::{
|
||||
EphemeralPublicKey, NullifierPublicKey, NullifierSecretKey, PublicKey, program::ProgramId,
|
||||
};
|
||||
|
||||
pub mod data;
|
||||
|
||||
#[derive(Copy, Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct Nonce(pub u128);
|
||||
#[derive(Copy, Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Identifier(pub u128);
|
||||
|
||||
impl Nonce {
|
||||
pub const fn public_account_nonce_increment(&mut self) {
|
||||
@ -91,6 +96,30 @@ impl BorshDeserialize for Nonce {
|
||||
|
||||
pub type Balance = u128;
|
||||
|
||||
impl Identifier {
|
||||
#[must_use]
|
||||
pub fn private_identifier(epk: &EphemeralPublicKey, index: u8) -> Self {
|
||||
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/LEE/v0.3/AccountId/Identifier/\x00";
|
||||
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
bytes.extend_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
|
||||
bytes.extend_from_slice(&epk.0);
|
||||
bytes.extend_from_slice(&[index]);
|
||||
|
||||
let mut value = [0_u8; 16];
|
||||
value.copy_from_slice(&Impl::hash_bytes(&bytes).as_bytes()[0..16]);
|
||||
|
||||
Self(u128::from_le_bytes(value))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new_os_random() -> Self {
|
||||
let mut bytes = [0_u8; 16];
|
||||
OsRng.fill_bytes(&mut bytes);
|
||||
Self(u128::from_le_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
/// Account to be used both in public and private contexts.
|
||||
#[derive(
|
||||
Default, Clone, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
@ -130,11 +159,12 @@ pub struct AccountWithMetadata {
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
impl AccountWithMetadata {
|
||||
pub fn new(account: Account, is_authorized: bool, account_id: impl Into<AccountId>) -> Self {
|
||||
#[must_use]
|
||||
pub const fn new(account: Account, is_authorized: bool, account_id: AccountId) -> Self {
|
||||
Self {
|
||||
account,
|
||||
is_authorized,
|
||||
account_id: account_id.into(),
|
||||
account_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,6 +207,42 @@ impl AccountId {
|
||||
pub const fn into_value(self) -> [u8; 32] {
|
||||
self.value
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn private_account_id(npk: &NullifierPublicKey, identifier: Identifier) -> Self {
|
||||
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] =
|
||||
b"/LEE/v0.3/AccountId/Private/\x00\x00\x00\x00";
|
||||
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
bytes.extend_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
|
||||
bytes.extend_from_slice(&npk.0);
|
||||
bytes.extend_from_slice(&identifier.0.to_le_bytes());
|
||||
|
||||
Self::new(
|
||||
Impl::hash_bytes(&bytes)
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.expect("Conversion should not fail"),
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn public_account_id(value: &PublicKey) -> Self {
|
||||
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] =
|
||||
b"/LEE/v0.3/AccountId/Public/\x00\x00\x00\x00\x00";
|
||||
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
bytes.extend_from_slice(PUBLIC_ACCOUNT_ID_PREFIX);
|
||||
bytes.extend_from_slice(value.value());
|
||||
// bytes.extend_from_slice(&identifier.0.to_le_bytes());
|
||||
|
||||
Self::new(
|
||||
Impl::hash_bytes(&bytes)
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.expect("Conversion should not fail"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for AccountId {
|
||||
@ -351,4 +417,57 @@ mod tests {
|
||||
|
||||
assert_eq!(nonce, nonce_restored);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_id_from_nullifier_public_key() {
|
||||
let nsk = [
|
||||
57, 5, 64, 115, 153, 56, 184, 51, 207, 238, 99, 165, 147, 214, 213, 151, 30, 251, 30,
|
||||
196, 134, 22, 224, 211, 237, 120, 136, 225, 188, 220, 249, 28,
|
||||
];
|
||||
let npk = NullifierPublicKey::from(&nsk);
|
||||
let expected_account_id = AccountId::new([
|
||||
48, 66, 236, 142, 62, 81, 247, 114, 151, 55, 109, 108, 34, 132, 216, 182, 239, 250,
|
||||
126, 85, 106, 222, 127, 193, 125, 168, 62, 150, 129, 194, 135, 114,
|
||||
]);
|
||||
|
||||
let identifier = Identifier(13_u128);
|
||||
|
||||
let account_id = AccountId::private_account_id(&npk, identifier);
|
||||
|
||||
assert_eq!(account_id, expected_account_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_id_from_public_key() {
|
||||
let pub_key = PublicKey::try_new([42_u8; 32]).expect("Expect valid Public Key");
|
||||
|
||||
let expected_account_id = AccountId::new([
|
||||
55, 223, 166, 27, 166, 126, 71, 128, 222, 225, 215, 176, 98, 21, 215, 13, 71, 74, 13,
|
||||
72, 200, 175, 25, 19, 96, 160, 250, 230, 45, 15, 254, 134,
|
||||
]);
|
||||
|
||||
let account_id = AccountId::public_account_id(&pub_key);
|
||||
|
||||
assert_eq!(account_id, expected_account_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identifier_from_ephemeral_public_key() {
|
||||
let epk = EphemeralPublicKey::from_scalar([
|
||||
185, 147, 32, 242, 145, 91, 123, 77, 42, 33, 134, 84, 12, 165, 117, 70, 158, 201, 95,
|
||||
153, 14, 12, 92, 235, 128, 156, 194, 169, 68, 35, 165, 127,
|
||||
]);
|
||||
|
||||
let expected_identifier = Identifier(u128::from_le_bytes([
|
||||
170, 216, 75, 182, 85, 117, 119, 230, 115, 121, 70, 204, 104, 96, 182, 122,
|
||||
]));
|
||||
let identifier = Identifier::private_identifier(&epk, 13_u8);
|
||||
|
||||
assert_eq!(identifier, expected_identifier);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_identifier() {
|
||||
assert_eq!(0_u128, Identifier::default().0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
Commitment, CommitmentSetDigest, MembershipProof, Nullifier, NullifierPublicKey,
|
||||
NullifierSecretKey, SharedSecretKey,
|
||||
account::{Account, AccountWithMetadata},
|
||||
account::{Account, AccountWithMetadata, Identifier},
|
||||
encryption::Ciphertext,
|
||||
program::{BlockValidityWindow, ProgramId, ProgramOutput, TimestampValidityWindow},
|
||||
};
|
||||
@ -22,6 +22,8 @@ pub struct PrivacyPreservingCircuitInput {
|
||||
pub private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>,
|
||||
/// Nullifier secret keys for authorized private accounts.
|
||||
pub private_account_nsks: Vec<NullifierSecretKey>,
|
||||
/// Identifiers used to generate `AccountId`.
|
||||
pub private_account_identifiers: Vec<Identifier>,
|
||||
/// Membership proofs for private accounts. Can be [`None`] for uninitialized accounts.
|
||||
pub private_account_membership_proofs: Vec<Option<MembershipProof>>,
|
||||
/// Program ID.
|
||||
@ -57,7 +59,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
Commitment, Nullifier, NullifierPublicKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Nonce},
|
||||
account::{Account, AccountId, AccountWithMetadata, Identifier, Nonce},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -93,12 +95,21 @@ mod tests {
|
||||
}],
|
||||
ciphertexts: vec![Ciphertext(vec![255, 255, 1, 1, 2, 2])],
|
||||
new_commitments: vec![Commitment::new(
|
||||
&NullifierPublicKey::from(&[1; 32]),
|
||||
&AccountId::private_account_id(
|
||||
&NullifierPublicKey::from(&[1_u8; 32]),
|
||||
Identifier(0_u128),
|
||||
),
|
||||
&Account::default(),
|
||||
)],
|
||||
new_nullifiers: vec![(
|
||||
Nullifier::for_account_update(
|
||||
&Commitment::new(&NullifierPublicKey::from(&[2; 32]), &Account::default()),
|
||||
&Commitment::new(
|
||||
&AccountId::private_account_id(
|
||||
&NullifierPublicKey::from(&[2_u8; 32]),
|
||||
Identifier(0_u128),
|
||||
),
|
||||
&Account::default(),
|
||||
),
|
||||
&[1; 32],
|
||||
),
|
||||
[0xab; 32],
|
||||
|
||||
@ -2,7 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use risc0_zkvm::sha::{Impl, Sha256 as _};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{NullifierPublicKey, account::Account};
|
||||
use crate::account::{Account, AccountId};
|
||||
|
||||
/// A commitment to all zero data.
|
||||
/// ```python
|
||||
@ -50,15 +50,15 @@ impl std::fmt::Debug for Commitment {
|
||||
|
||||
impl Commitment {
|
||||
/// Generates the commitment to a private account owned by user for npk:
|
||||
/// SHA256( `Comm_DS` || npk || `program_owner` || balance || nonce || SHA256(data)).
|
||||
/// SHA256( `Comm_DS` || `account_id` || `program_owner` || balance || nonce || SHA256(data)).
|
||||
#[must_use]
|
||||
pub fn new(npk: &NullifierPublicKey, account: &Account) -> Self {
|
||||
pub fn new(account_id: &AccountId, account: &Account) -> Self {
|
||||
const COMMITMENT_PREFIX: &[u8; 32] =
|
||||
b"/LEE/v0.3/Commitment/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(COMMITMENT_PREFIX);
|
||||
bytes.extend_from_slice(&npk.to_byte_array());
|
||||
bytes.extend_from_slice(account_id.value());
|
||||
let account_bytes_with_hashed_data = {
|
||||
let mut this = Vec::new();
|
||||
for word in &account.program_owner {
|
||||
@ -115,14 +115,15 @@ mod tests {
|
||||
use risc0_zkvm::sha::{Impl, Sha256 as _};
|
||||
|
||||
use crate::{
|
||||
Commitment, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, NullifierPublicKey, account::Account,
|
||||
Commitment, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH,
|
||||
account::{Account, AccountId},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn nothing_up_my_sleeve_dummy_commitment() {
|
||||
let default_account = Account::default();
|
||||
let npk_null = NullifierPublicKey([0; 32]);
|
||||
let expected_dummy_commitment = Commitment::new(&npk_null, &default_account);
|
||||
let account_id = AccountId::new([0; 32]);
|
||||
let expected_dummy_commitment = Commitment::new(&account_id, &default_account);
|
||||
assert_eq!(DUMMY_COMMITMENT, expected_dummy_commitment);
|
||||
}
|
||||
|
||||
|
||||
@ -5,11 +5,11 @@ use chacha20::{
|
||||
};
|
||||
use risc0_zkvm::sha::{Impl, Sha256 as _};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use shared_key_derivation::EphemeralPublicKey;
|
||||
#[cfg(feature = "host")]
|
||||
pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey};
|
||||
pub use shared_key_derivation::{EphemeralSecretKey, ViewingPublicKey};
|
||||
|
||||
use crate::{Commitment, account::Account};
|
||||
#[cfg(feature = "host")]
|
||||
pub mod shared_key_derivation;
|
||||
|
||||
pub type Scalar = [u8; 32];
|
||||
|
||||
@ -9,4 +9,13 @@ pub enum NssaCoreError {
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
|
||||
#[error("Invalid Public Key")]
|
||||
InvalidPublicKey(#[source] k256::schnorr::Error),
|
||||
|
||||
#[error("Invalid hex for public key")]
|
||||
InvalidHexPublicKey(hex::FromHexError),
|
||||
|
||||
#[error("Invalid private key")]
|
||||
InvalidPrivateKey,
|
||||
}
|
||||
|
||||
@ -8,8 +8,11 @@ pub use commitment::{
|
||||
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof,
|
||||
compute_digest_for_path,
|
||||
};
|
||||
pub use encryption::{EncryptionScheme, SharedSecretKey};
|
||||
pub use encryption::{
|
||||
EncryptionScheme, SharedSecretKey, shared_key_derivation::EphemeralPublicKey,
|
||||
};
|
||||
pub use nullifier::{Nullifier, NullifierPublicKey, NullifierSecretKey};
|
||||
pub use signature::{PrivateKey, PublicKey, Signature};
|
||||
|
||||
pub mod account;
|
||||
mod circuit_io;
|
||||
@ -18,8 +21,9 @@ mod encoding;
|
||||
pub mod encryption;
|
||||
mod nullifier;
|
||||
pub mod program;
|
||||
pub mod signature;
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
// TODO: temp#[cfg(feature = "host")]
|
||||
pub mod error;
|
||||
|
||||
pub type BlockId = u64;
|
||||
|
||||
@ -8,23 +8,6 @@ use crate::{Commitment, account::AccountId};
|
||||
#[cfg_attr(any(feature = "host", test), derive(Clone, Hash))]
|
||||
pub struct NullifierPublicKey(pub [u8; 32]);
|
||||
|
||||
impl From<&NullifierPublicKey> for AccountId {
|
||||
fn from(value: &NullifierPublicKey) -> Self {
|
||||
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] =
|
||||
b"/LEE/v0.3/AccountId/Private/\x00\x00\x00\x00";
|
||||
|
||||
let mut bytes = [0; 64];
|
||||
bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
|
||||
bytes[32..].copy_from_slice(&value.0);
|
||||
Self::new(
|
||||
Impl::hash_bytes(&bytes)
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.expect("Conversion should not fail"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for NullifierPublicKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_slice()
|
||||
@ -85,10 +68,10 @@ impl Nullifier {
|
||||
|
||||
/// Computes a nullifier for an account initialization.
|
||||
#[must_use]
|
||||
pub fn for_account_initialization(npk: &NullifierPublicKey) -> Self {
|
||||
pub fn for_account_initialization(account_id: &AccountId) -> Self {
|
||||
const INIT_PREFIX: &[u8; 32] = b"/LEE/v0.3/Nullifier/Initialize/\x00";
|
||||
let mut bytes = INIT_PREFIX.to_vec();
|
||||
bytes.extend_from_slice(&npk.to_byte_array());
|
||||
bytes.extend_from_slice(account_id.value());
|
||||
Self(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
@ -96,6 +79,7 @@ impl Nullifier {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::account::Identifier;
|
||||
|
||||
#[test]
|
||||
fn constructor_for_account_update() {
|
||||
@ -115,11 +99,16 @@ mod tests {
|
||||
112, 188, 193, 129, 150, 55, 228, 67, 88, 168, 29, 151, 5, 92, 23, 190, 17, 162, 164,
|
||||
255, 29, 105, 42, 186, 43, 11, 157, 168, 132, 225, 17, 163,
|
||||
]);
|
||||
|
||||
let identifier = Identifier(0_u128);
|
||||
|
||||
let account_id = AccountId::private_account_id(&npk, identifier);
|
||||
|
||||
let expected_nullifier = Nullifier([
|
||||
149, 59, 95, 181, 2, 194, 20, 143, 72, 233, 104, 243, 59, 70, 67, 243, 110, 77, 109,
|
||||
132, 139, 111, 51, 125, 128, 92, 107, 46, 252, 4, 20, 149,
|
||||
63, 58, 51, 159, 15, 100, 240, 243, 60, 143, 151, 108, 116, 144, 101, 6, 134, 72, 198,
|
||||
249, 108, 80, 237, 194, 143, 66, 225, 191, 111, 49, 66, 54,
|
||||
]);
|
||||
let nullifier = Nullifier::for_account_initialization(&npk);
|
||||
let nullifier = Nullifier::for_account_initialization(&account_id);
|
||||
assert_eq!(nullifier, expected_nullifier);
|
||||
}
|
||||
|
||||
@ -136,21 +125,4 @@ mod tests {
|
||||
let npk = NullifierPublicKey::from(&nsk);
|
||||
assert_eq!(npk, expected_npk);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_id_from_nullifier_public_key() {
|
||||
let nsk = [
|
||||
57, 5, 64, 115, 153, 56, 184, 51, 207, 238, 99, 165, 147, 214, 213, 151, 30, 251, 30,
|
||||
196, 134, 22, 224, 211, 237, 120, 136, 225, 188, 220, 249, 28,
|
||||
];
|
||||
let npk = NullifierPublicKey::from(&nsk);
|
||||
let expected_account_id = AccountId::new([
|
||||
139, 72, 194, 222, 215, 187, 147, 56, 55, 35, 222, 205, 156, 12, 204, 227, 166, 44, 30,
|
||||
81, 186, 14, 167, 234, 28, 236, 32, 213, 125, 251, 193, 233,
|
||||
]);
|
||||
|
||||
let account_id = AccountId::from(&npk);
|
||||
|
||||
assert_eq!(account_id, expected_account_id);
|
||||
}
|
||||
}
|
||||
|
||||
367
nssa/core/src/signature/bip340_test_vectors.rs
Normal file
367
nssa/core/src/signature/bip340_test_vectors.rs
Normal file
@ -0,0 +1,367 @@
|
||||
use crate::{PrivateKey, PublicKey, Signature};
|
||||
|
||||
pub struct TestVector {
|
||||
pub seckey: Option<PrivateKey>,
|
||||
pub pubkey: PublicKey,
|
||||
pub aux_rand: Option<[u8; 32]>,
|
||||
pub message: Option<Vec<u8>>,
|
||||
pub signature: Signature,
|
||||
pub verification_result: bool,
|
||||
}
|
||||
|
||||
/// Test vectors from
|
||||
/// <https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv>.
|
||||
//
|
||||
pub fn test_vectors() -> Vec<TestVector> {
|
||||
vec![
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0000000000000000000000000000000000000000000000000000000000000003",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
)),
|
||||
message: Some(
|
||||
hex::decode("0000000000000000000000000000000000000000000000000000000000000000")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
)),
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906",
|
||||
)),
|
||||
message: Some(
|
||||
hex::decode("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
)),
|
||||
message: Some(
|
||||
hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
// Test with invalid public key
|
||||
// TestVector {
|
||||
// seckey: None,
|
||||
// pubkey: PublicKey::new(hex_to_bytes(
|
||||
// "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34",
|
||||
// )).unwrap(),
|
||||
// aux_rand: None,
|
||||
// message: Some(
|
||||
// hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89").unwrap(),
|
||||
// ),
|
||||
// signature: Signature {
|
||||
// value: hex_to_bytes(
|
||||
// "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||
// ),
|
||||
// },
|
||||
// verification_result: false,
|
||||
// },
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
TestVector {
|
||||
seckey: None,
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
)).unwrap(),
|
||||
aux_rand: None,
|
||||
message: Some(
|
||||
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||
.unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
|
||||
),
|
||||
},
|
||||
verification_result: false,
|
||||
},
|
||||
// Test with invalid public key
|
||||
// TestVector {
|
||||
// seckey: None,
|
||||
// pubkey: PublicKey::new(hex_to_bytes(
|
||||
// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30",
|
||||
// )).unwrap(),
|
||||
// aux_rand: None,
|
||||
// message: Some(
|
||||
// hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89").unwrap(),
|
||||
// ),
|
||||
// signature: Signature {
|
||||
// value: hex_to_bytes(
|
||||
// "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||
// ),
|
||||
// },
|
||||
// verification_result: false,
|
||||
// },
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
)),
|
||||
message: None,
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
)),
|
||||
message: Some(hex::decode("11").unwrap()),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
)),
|
||||
message: Some(hex::decode("0102030405060708090A0B0C0D0E0F1011").unwrap()),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
TestVector {
|
||||
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||
)).unwrap()),
|
||||
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||
)).unwrap(),
|
||||
aux_rand: Some(hex_to_bytes::<32>(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
)),
|
||||
message: Some(
|
||||
hex::decode("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999").unwrap(),
|
||||
),
|
||||
signature: Signature {
|
||||
value: hex_to_bytes(
|
||||
"403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367",
|
||||
),
|
||||
},
|
||||
verification_result: true,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn hex_to_bytes<const N: usize>(hex: &str) -> [u8; N] {
|
||||
hex::decode(hex).unwrap().try_into().unwrap()
|
||||
}
|
||||
127
nssa/core/src/signature/mod.rs
Normal file
127
nssa/core/src/signature/mod.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
pub use private_key::PrivateKey;
|
||||
pub use public_key::PublicKey;
|
||||
use rand::{RngCore as _, rngs::OsRng};
|
||||
|
||||
mod private_key;
|
||||
mod public_key;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Signature {
|
||||
pub value: [u8; 64],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Signature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", hex::encode(self.value))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Signature {
|
||||
type Err = hex::FromHexError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut bytes = [0_u8; 64];
|
||||
hex::decode_to_slice(s, &mut bytes)?;
|
||||
Ok(Self { value: bytes })
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
#[must_use]
|
||||
pub fn new(key: &PrivateKey, message: &[u8]) -> Self {
|
||||
let mut aux_random = [0_u8; 32];
|
||||
OsRng.fill_bytes(&mut aux_random);
|
||||
Self::new_with_aux_random(key, message, aux_random)
|
||||
}
|
||||
|
||||
pub(crate) fn new_with_aux_random(
|
||||
key: &PrivateKey,
|
||||
message: &[u8],
|
||||
aux_random: [u8; 32],
|
||||
) -> Self {
|
||||
let value = {
|
||||
let signing_key = k256::schnorr::SigningKey::from_bytes(key.value())
|
||||
.expect("Expect valid signing key");
|
||||
signing_key
|
||||
.sign_raw(message, &aux_random)
|
||||
.expect("Expect to produce a valid signature")
|
||||
.to_bytes()
|
||||
};
|
||||
|
||||
Self { value }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_valid_for(&self, bytes: &[u8], public_key: &PublicKey) -> bool {
|
||||
let Ok(pk) = k256::schnorr::VerifyingKey::from_bytes(public_key.value()) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Ok(sig) = k256::schnorr::Signature::try_from(self.value.as_slice()) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
pk.verify_raw(bytes, &sig).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-utils")]
|
||||
#[must_use]
|
||||
pub const fn new_for_tests(value: [u8; 64]) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bip340_test_vectors;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::{Signature, signature::bip340_test_vectors};
|
||||
|
||||
#[test]
|
||||
fn signature_generation_from_bip340_test_vectors() {
|
||||
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||
let Some(private_key) = test_vector.seckey else {
|
||||
continue;
|
||||
};
|
||||
let Some(aux_random) = test_vector.aux_rand else {
|
||||
continue;
|
||||
};
|
||||
let Some(message) = test_vector.message else {
|
||||
continue;
|
||||
};
|
||||
if !test_vector.verification_result {
|
||||
continue;
|
||||
}
|
||||
let expected_signature = &test_vector.signature;
|
||||
|
||||
let signature = Signature::new_with_aux_random(&private_key, &message, aux_random);
|
||||
|
||||
assert_eq!(&signature, expected_signature, "Failed test vector {i}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signature_verification_from_bip340_test_vectors() {
|
||||
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||
let message = test_vector.message.unwrap_or(vec![]);
|
||||
let expected_result = test_vector.verification_result;
|
||||
|
||||
let result = test_vector
|
||||
.signature
|
||||
.is_valid_for(&message, &test_vector.pubkey);
|
||||
|
||||
assert_eq!(result, expected_result, "Failed test vector {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
78
nssa/core/src/signature/private_key.rs
Normal file
78
nssa/core/src/signature/private_key.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use rand::{Rng as _, rngs::OsRng};
|
||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||
|
||||
use crate::error::NssaCoreError;
|
||||
|
||||
// TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons
|
||||
// TODO: Implement Zeroize
|
||||
#[derive(Clone, SerializeDisplay, DeserializeFromStr, PartialEq, Eq)]
|
||||
pub struct PrivateKey([u8; 32]);
|
||||
|
||||
impl std::fmt::Debug for PrivateKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PrivateKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", hex::encode(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PrivateKey {
|
||||
type Err = NssaCoreError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut bytes = [0_u8; 32];
|
||||
hex::decode_to_slice(s, &mut bytes).map_err(|_err| NssaCoreError::InvalidPrivateKey)?;
|
||||
Self::try_new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrivateKey {
|
||||
#[must_use]
|
||||
pub fn new_os_random() -> Self {
|
||||
let mut rng = OsRng;
|
||||
|
||||
loop {
|
||||
if let Ok(key) = Self::try_new(rng.r#gen()) {
|
||||
break key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_key(value: [u8; 32]) -> bool {
|
||||
k256::SecretKey::from_bytes(&value.into()).is_ok()
|
||||
}
|
||||
|
||||
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaCoreError> {
|
||||
if Self::is_valid_key(value) {
|
||||
Ok(Self(value))
|
||||
} else {
|
||||
Err(NssaCoreError::InvalidPrivateKey)
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn value(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn value_getter() {
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
assert_eq!(key.value(), &key.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn produce_key() {
|
||||
let _key = PrivateKey::new_os_random();
|
||||
}
|
||||
}
|
||||
135
nssa/core/src/signature/public_key.rs
Normal file
135
nssa/core/src/signature/public_key.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use k256::elliptic_curve::sec1::ToEncodedPoint as _;
|
||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||
|
||||
use crate::{PrivateKey, error::NssaCoreError};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, BorshSerialize, SerializeDisplay, DeserializeFromStr)]
|
||||
pub struct PublicKey([u8; 32]);
|
||||
|
||||
impl std::fmt::Debug for PublicKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PublicKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", hex::encode(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PublicKey {
|
||||
type Err = NssaCoreError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut bytes = [0_u8; 32];
|
||||
hex::decode_to_slice(s, &mut bytes).map_err(NssaCoreError::InvalidHexPublicKey)?;
|
||||
Self::try_new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl BorshDeserialize for PublicKey {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut buf = [0_u8; 32];
|
||||
reader.read_exact(&mut buf)?;
|
||||
|
||||
Self::try_new(buf).map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicKey {
|
||||
#[must_use]
|
||||
pub fn new_from_private_key(key: &PrivateKey) -> Self {
|
||||
let value = {
|
||||
let secret_key = k256::SecretKey::from_bytes(&(*key.value()).into())
|
||||
.expect("Expect a valid private key");
|
||||
|
||||
let encoded = secret_key.public_key().to_encoded_point(false);
|
||||
let x_only = encoded
|
||||
.x()
|
||||
.expect("Expect k256 point to have a x-coordinate");
|
||||
|
||||
*x_only.first_chunk().expect("x_only is exactly 32 bytes")
|
||||
};
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaCoreError> {
|
||||
// Check point is a valid x-only public key
|
||||
let _ = k256::schnorr::VerifyingKey::from_bytes(&value)
|
||||
.map_err(NssaCoreError::InvalidPublicKey)?;
|
||||
|
||||
Ok(Self(value))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn value(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{PublicKey, error::NssaCoreError, signature::bip340_test_vectors};
|
||||
|
||||
#[test]
|
||||
fn try_new_invalid_public_key_from_bip340_test_vectors_5() {
|
||||
let value_invalid_key = [
|
||||
238, 253, 234, 76, 219, 103, 119, 80, 164, 32, 254, 232, 7, 234, 207, 33, 235, 152,
|
||||
152, 174, 121, 185, 118, 135, 102, 228, 250, 160, 74, 45, 74, 52,
|
||||
];
|
||||
|
||||
let result = PublicKey::try_new(value_invalid_key);
|
||||
|
||||
assert!(matches!(result, Err(NssaCoreError::InvalidPublicKey(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_new_invalid_public_key_from_bip340_test_vector_14() {
|
||||
let value_invalid_key = [
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 252, 48,
|
||||
];
|
||||
|
||||
let result = PublicKey::try_new(value_invalid_key);
|
||||
|
||||
assert!(matches!(result, Err(NssaCoreError::InvalidPublicKey(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_new_valid_public_keys() {
|
||||
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||
let expected_public_key = test_vector.pubkey;
|
||||
let public_key = PublicKey::try_new(*expected_public_key.value()).unwrap();
|
||||
assert_eq!(public_key, expected_public_key, "Failed on test vector {i}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_key_generation_from_bip340_test_vectors() {
|
||||
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||
let Some(private_key) = &test_vector.seckey else {
|
||||
continue;
|
||||
};
|
||||
let public_key = PublicKey::new_from_private_key(private_key);
|
||||
let expected_public_key = &test_vector.pubkey;
|
||||
assert_eq!(
|
||||
&public_key, expected_public_key,
|
||||
"Failed test vector at index {i}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correct_ser_deser_roundtrip() {
|
||||
let pub_key = PublicKey::try_new([42; 32]).unwrap();
|
||||
|
||||
let pub_key_borsh_ser = borsh::to_vec(&pub_key).unwrap();
|
||||
let pub_key_new: PublicKey = borsh::from_slice(&pub_key_borsh_ser).unwrap();
|
||||
|
||||
assert_eq!(pub_key, pub_key_new);
|
||||
}
|
||||
}
|
||||
@ -22,18 +22,9 @@ pub enum NssaError {
|
||||
#[error("Serialization error: {0}")]
|
||||
InstructionSerializationError(String),
|
||||
|
||||
#[error("Invalid private key")]
|
||||
InvalidPrivateKey,
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
|
||||
#[error("Invalid Public Key")]
|
||||
InvalidPublicKey(#[source] k256::schnorr::Error),
|
||||
|
||||
#[error("Invalid hex for public key")]
|
||||
InvalidHexPublicKey(hex::FromHexError),
|
||||
|
||||
#[error("Risc0 error: {0}")]
|
||||
ProgramWriteInputFailed(String),
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ pub use privacy_preserving_transaction::{
|
||||
pub use program_deployment_transaction::ProgramDeploymentTransaction;
|
||||
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
|
||||
pub use public_transaction::PublicTransaction;
|
||||
pub use signature::{PrivateKey, PublicKey, Signature};
|
||||
pub use state::{
|
||||
CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_PROGRAM_ACCOUNT_IDS, V03State,
|
||||
@ -29,7 +28,6 @@ pub mod privacy_preserving_transaction;
|
||||
pub mod program;
|
||||
pub mod program_deployment_transaction;
|
||||
pub mod public_transaction;
|
||||
mod signature;
|
||||
mod state;
|
||||
mod validated_state_diff;
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput,
|
||||
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||
account::AccountWithMetadata,
|
||||
account::{AccountWithMetadata, Identifier},
|
||||
program::{ChainedCall, InstructionData, ProgramId, ProgramOutput},
|
||||
};
|
||||
use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover};
|
||||
@ -63,13 +63,14 @@ impl From<Program> for ProgramWithDependencies {
|
||||
|
||||
/// Generates a proof of the execution of a NSSA program inside the privacy preserving execution
|
||||
/// circuit.
|
||||
/// TODO: too many parameters.
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: fix this later")]
|
||||
pub fn execute_and_prove(
|
||||
pre_states: Vec<AccountWithMetadata>,
|
||||
instruction_data: InstructionData,
|
||||
visibility_mask: Vec<u8>,
|
||||
private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>,
|
||||
private_account_nsks: Vec<NullifierSecretKey>,
|
||||
private_account_identifiers: Vec<Identifier>,
|
||||
private_account_membership_proofs: Vec<Option<MembershipProof>>,
|
||||
program_with_dependencies: &ProgramWithDependencies,
|
||||
) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> {
|
||||
@ -129,6 +130,7 @@ pub fn execute_and_prove(
|
||||
visibility_mask,
|
||||
private_account_keys,
|
||||
private_account_nsks,
|
||||
private_account_identifiers,
|
||||
private_account_membership_proofs,
|
||||
program_id: program_with_dependencies.program.id(),
|
||||
};
|
||||
@ -183,7 +185,7 @@ mod tests {
|
||||
|
||||
use nssa_core::{
|
||||
Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier, SharedSecretKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
|
||||
account::{Account, AccountId, AccountWithMetadata, Identifier, Nonce, data::Data},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -214,7 +216,7 @@ mod tests {
|
||||
let recipient = AccountWithMetadata::new(
|
||||
Account::default(),
|
||||
false,
|
||||
AccountId::from(&recipient_keys.npk()),
|
||||
AccountId::private_account_id(&recipient_keys.npk(), recipient_keys.identifier),
|
||||
);
|
||||
|
||||
let balance_to_move: u128 = 37;
|
||||
@ -244,6 +246,7 @@ mod tests {
|
||||
vec![0, 2],
|
||||
vec![(recipient_keys.npk(), shared_secret)],
|
||||
vec![],
|
||||
vec![recipient_keys.identifier],
|
||||
vec![None],
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
)
|
||||
@ -274,6 +277,8 @@ mod tests {
|
||||
let program = Program::authenticated_transfer_program();
|
||||
let sender_keys = test_private_account_keys_1();
|
||||
let recipient_keys = test_private_account_keys_2();
|
||||
let recipient_id =
|
||||
AccountId::private_account_id(&recipient_keys.npk(), recipient_keys.identifier);
|
||||
|
||||
let sender_nonce = Nonce(0xdead_beef);
|
||||
let sender_pre = AccountWithMetadata::new(
|
||||
@ -284,14 +289,14 @@ mod tests {
|
||||
data: Data::default(),
|
||||
},
|
||||
true,
|
||||
AccountId::from(&sender_keys.npk()),
|
||||
AccountId::private_account_id(&sender_keys.npk(), sender_keys.identifier),
|
||||
);
|
||||
let commitment_sender = Commitment::new(&sender_keys.npk(), &sender_pre.account);
|
||||
let commitment_sender = Commitment::new(&sender_pre.account_id, &sender_pre.account);
|
||||
|
||||
let recipient = AccountWithMetadata::new(
|
||||
Account::default(),
|
||||
false,
|
||||
AccountId::from(&recipient_keys.npk()),
|
||||
AccountId::private_account_id(&recipient_keys.npk(), recipient_keys.identifier),
|
||||
);
|
||||
let balance_to_move: u128 = 37;
|
||||
|
||||
@ -304,7 +309,7 @@ mod tests {
|
||||
commitment_set.digest(),
|
||||
),
|
||||
(
|
||||
Nullifier::for_account_initialization(&recipient_keys.npk()),
|
||||
Nullifier::for_account_initialization(&recipient_id),
|
||||
DUMMY_COMMITMENT_HASH,
|
||||
),
|
||||
];
|
||||
@ -324,8 +329,8 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let expected_new_commitments = vec![
|
||||
Commitment::new(&sender_keys.npk(), &expected_private_account_1),
|
||||
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
||||
Commitment::new(&sender_pre.account_id, &expected_private_account_1),
|
||||
Commitment::new(&recipient.account_id, &expected_private_account_2),
|
||||
];
|
||||
|
||||
let esk_1 = [3; 32];
|
||||
@ -343,6 +348,7 @@ mod tests {
|
||||
(recipient_keys.npk(), shared_secret_2),
|
||||
],
|
||||
vec![sender_keys.nsk],
|
||||
vec![sender_keys.identifier, recipient_keys.identifier],
|
||||
vec![commitment_set.get_proof_for(&commitment_sender), None],
|
||||
&program.into(),
|
||||
)
|
||||
@ -380,7 +386,7 @@ mod tests {
|
||||
let pre = AccountWithMetadata::new(
|
||||
Account::default(),
|
||||
false,
|
||||
AccountId::from(&account_keys.npk()),
|
||||
AccountId::private_account_id(&account_keys.npk(), Identifier(42_u128)),
|
||||
);
|
||||
|
||||
let validity_window_chain_caller = Program::validity_window_chain_caller();
|
||||
@ -409,6 +415,7 @@ mod tests {
|
||||
vec![2],
|
||||
vec![(account_keys.npk(), shared_secret)],
|
||||
vec![],
|
||||
vec![Identifier(42_u128)],
|
||||
vec![None],
|
||||
&program_with_deps,
|
||||
);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitOutput,
|
||||
Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, Nonce},
|
||||
encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey},
|
||||
program::{BlockValidityWindow, TimestampValidityWindow},
|
||||
@ -21,11 +21,11 @@ pub struct EncryptedAccountData {
|
||||
impl EncryptedAccountData {
|
||||
fn new(
|
||||
ciphertext: Ciphertext,
|
||||
npk: &NullifierPublicKey,
|
||||
account_id: &AccountId,
|
||||
vpk: &ViewingPublicKey,
|
||||
epk: EphemeralPublicKey,
|
||||
) -> Self {
|
||||
let view_tag = Self::compute_view_tag(npk, vpk);
|
||||
let view_tag = Self::compute_view_tag(account_id, vpk);
|
||||
Self {
|
||||
ciphertext,
|
||||
epk,
|
||||
@ -35,10 +35,13 @@ impl EncryptedAccountData {
|
||||
|
||||
/// Computes the tag as the first byte of SHA256("/LEE/v0.3/ViewTag/" || Npk || vpk).
|
||||
#[must_use]
|
||||
pub fn compute_view_tag(npk: &NullifierPublicKey, vpk: &ViewingPublicKey) -> ViewTag {
|
||||
pub fn compute_view_tag(account_id: &AccountId, vpk: &ViewingPublicKey) -> ViewTag {
|
||||
const VIEWTAG_PREFIX: &[u8; 32] =
|
||||
b"/LEE/v0.3/ViewTag\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(b"/LEE/v0.3/ViewTag/");
|
||||
hasher.update(npk.to_byte_array());
|
||||
hasher.update(VIEWTAG_PREFIX);
|
||||
hasher.update(account_id.to_bytes());
|
||||
hasher.update(vpk.to_bytes());
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
digest[0]
|
||||
@ -90,7 +93,10 @@ impl Message {
|
||||
pub fn try_from_circuit_output(
|
||||
public_account_ids: Vec<AccountId>,
|
||||
nonces: Vec<Nonce>,
|
||||
public_keys: Vec<(NullifierPublicKey, ViewingPublicKey, EphemeralPublicKey)>,
|
||||
public_keys: Vec<(AccountId, ViewingPublicKey, EphemeralPublicKey)>, /* TODO: Rename
|
||||
* `public_keys` to
|
||||
* account for
|
||||
* `account_id`. */
|
||||
output: PrivacyPreservingCircuitOutput,
|
||||
) -> Result<Self, NssaError> {
|
||||
if public_keys.len() != output.ciphertexts.len() {
|
||||
@ -103,8 +109,8 @@ impl Message {
|
||||
.ciphertexts
|
||||
.into_iter()
|
||||
.zip(public_keys)
|
||||
.map(|(ciphertext, (npk, vpk, epk))| {
|
||||
EncryptedAccountData::new(ciphertext, &npk, &vpk, epk)
|
||||
.map(|(ciphertext, (account_id, vpk, epk))| {
|
||||
EncryptedAccountData::new(ciphertext, &account_id, &vpk, epk)
|
||||
})
|
||||
.collect();
|
||||
Ok(Self {
|
||||
@ -124,7 +130,7 @@ impl Message {
|
||||
pub mod tests {
|
||||
use nssa_core::{
|
||||
Commitment, EncryptionScheme, Nullifier, NullifierPublicKey, SharedSecretKey,
|
||||
account::Account,
|
||||
account::{Account, Identifier},
|
||||
encryption::{EphemeralPublicKey, ViewingPublicKey},
|
||||
program::{BlockValidityWindow, TimestampValidityWindow},
|
||||
};
|
||||
@ -146,7 +152,9 @@ pub mod tests {
|
||||
let npk1 = NullifierPublicKey::from(&nsk1);
|
||||
let npk2 = NullifierPublicKey::from(&nsk2);
|
||||
|
||||
let public_account_ids = vec![AccountId::new([1; 32])];
|
||||
let account_id1 = AccountId::private_account_id(&npk1, Identifier(0_u128));
|
||||
let account_id2 = AccountId::private_account_id(&npk2, Identifier(0_u128));
|
||||
let public_account_ids = vec![account_id1, account_id2];
|
||||
|
||||
let nonces = vec![1_u128.into(), 2_u128.into(), 3_u128.into()];
|
||||
|
||||
@ -154,9 +162,9 @@ pub mod tests {
|
||||
|
||||
let encrypted_private_post_states = Vec::new();
|
||||
|
||||
let new_commitments = vec![Commitment::new(&npk2, &account2)];
|
||||
let new_commitments = vec![Commitment::new(&account_id2, &account2)];
|
||||
|
||||
let old_commitment = Commitment::new(&npk1, &account1);
|
||||
let old_commitment = Commitment::new(&account_id1, &account1);
|
||||
let new_nullifiers = vec![(
|
||||
Nullifier::for_account_update(&old_commitment, &nsk1),
|
||||
[0; 32],
|
||||
@ -178,19 +186,22 @@ pub mod tests {
|
||||
fn encrypted_account_data_constructor() {
|
||||
let npk = NullifierPublicKey::from(&[1; 32]);
|
||||
let vpk = ViewingPublicKey::from_scalar([2; 32]);
|
||||
let account_id = AccountId::private_account_id(&npk, Identifier(0_u128));
|
||||
let account = Account::default();
|
||||
let commitment = Commitment::new(&npk, &account);
|
||||
let commitment = Commitment::new(&account_id, &account);
|
||||
let esk = [3; 32];
|
||||
let shared_secret = SharedSecretKey::new(&esk, &vpk);
|
||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||
let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2);
|
||||
let encrypted_account_data =
|
||||
EncryptedAccountData::new(ciphertext.clone(), &npk, &vpk, epk.clone());
|
||||
EncryptedAccountData::new(ciphertext.clone(), &account_id, &vpk, epk.clone());
|
||||
|
||||
let expected_view_tag = {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(b"/LEE/v0.3/ViewTag/");
|
||||
hasher.update(npk.to_byte_array());
|
||||
hasher.update(
|
||||
b"/LEE/v0.3/ViewTag\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
);
|
||||
hasher.update(account_id.to_bytes());
|
||||
hasher.update(vpk.to_bytes());
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
digest[0]
|
||||
@ -200,7 +211,7 @@ pub mod tests {
|
||||
assert_eq!(encrypted_account_data.epk, epk);
|
||||
assert_eq!(
|
||||
encrypted_account_data.view_tag,
|
||||
EncryptedAccountData::compute_view_tag(&npk, &vpk)
|
||||
EncryptedAccountData::compute_view_tag(&account_id, &vpk)
|
||||
);
|
||||
assert_eq!(encrypted_account_data.view_tag, expected_view_tag);
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ impl PrivacyPreservingTransaction {
|
||||
self.witness_set
|
||||
.signatures_and_public_keys()
|
||||
.iter()
|
||||
.map(|(_, public_key)| AccountId::from(public_key))
|
||||
.map(|(_, public_key)| AccountId::public_account_id(public_key))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -61,8 +61,10 @@ impl PrivacyPreservingTransaction {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nssa_core::{PrivateKey, PublicKey};
|
||||
|
||||
use crate::{
|
||||
AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey,
|
||||
AccountId, PrivacyPreservingTransaction,
|
||||
privacy_preserving_transaction::{
|
||||
circuit::Proof, message::tests::message_for_tests, witness_set::WitnessSet,
|
||||
},
|
||||
@ -71,8 +73,8 @@ mod tests {
|
||||
fn keys_for_tests() -> (PrivateKey, PrivateKey, AccountId, AccountId) {
|
||||
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
|
||||
let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
|
||||
let addr1 = AccountId::public_account_id(&PublicKey::new_from_private_key(&key1));
|
||||
let addr2 = AccountId::public_account_id(&PublicKey::new_from_private_key(&key2));
|
||||
(key1, key2, addr1, addr2)
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{PrivateKey, PublicKey, Signature};
|
||||
|
||||
use crate::{
|
||||
PrivateKey, PublicKey, Signature,
|
||||
privacy_preserving_transaction::{circuit::Proof, message::Message},
|
||||
};
|
||||
use crate::privacy_preserving_transaction::{circuit::Proof, message::Message};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct WitnessSet {
|
||||
|
||||
@ -35,7 +35,7 @@ impl PublicTransaction {
|
||||
self.witness_set
|
||||
.signatures_and_public_keys()
|
||||
.iter()
|
||||
.map(|(_, public_key)| AccountId::from(public_key))
|
||||
.map(|(_, public_key)| AccountId::public_account_id(public_key))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -61,10 +61,11 @@ impl PublicTransaction {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use nssa_core::{PrivateKey, PublicKey};
|
||||
use sha2::{Digest as _, digest::FixedOutput as _};
|
||||
|
||||
use crate::{
|
||||
AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V03State,
|
||||
AccountId, PublicTransaction, V03State,
|
||||
error::NssaError,
|
||||
program::Program,
|
||||
public_transaction::{Message, WitnessSet},
|
||||
@ -74,8 +75,8 @@ pub mod tests {
|
||||
fn keys_for_tests() -> (PrivateKey, PrivateKey, AccountId, AccountId) {
|
||||
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
|
||||
let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
|
||||
let addr1 = AccountId::public_account_id(&PublicKey::new_from_private_key(&key1));
|
||||
let addr2 = AccountId::public_account_id(&PublicKey::new_from_private_key(&key2));
|
||||
(key1, key2, addr1, addr2)
|
||||
}
|
||||
|
||||
@ -201,8 +202,11 @@ pub mod tests {
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-utils")]
|
||||
#[test]
|
||||
fn all_signatures_must_be_valid() {
|
||||
use nssa_core::Signature;
|
||||
|
||||
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||
let state = state_for_tests();
|
||||
let nonces = vec![0_u128.into(), 0_u128.into()];
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{PrivateKey, PublicKey, Signature};
|
||||
|
||||
use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message};
|
||||
use crate::public_transaction::Message;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct WitnessSet {
|
||||
@ -65,8 +66,8 @@ mod tests {
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let pubkey1 = PublicKey::new_from_private_key(&key1);
|
||||
let pubkey2 = PublicKey::new_from_private_key(&key2);
|
||||
let addr1 = AccountId::from(&pubkey1);
|
||||
let addr2 = AccountId::from(&pubkey2);
|
||||
let addr1 = AccountId::public_account_id(&pubkey1);
|
||||
let addr2 = AccountId::public_account_id(&pubkey2);
|
||||
let nonces = vec![1_u128.into(), 2_u128.into()];
|
||||
let instruction = vec![1, 2, 3, 4];
|
||||
let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT_HASH, EncryptionScheme, MembershipProof,
|
||||
Nullifier, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput,
|
||||
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Nonce},
|
||||
account::{Account, AccountId, AccountWithMetadata, Identifier, Nonce},
|
||||
compute_digest_for_path,
|
||||
program::{
|
||||
AccountPostState, BlockValidityWindow, ChainedCall, Claim, DEFAULT_PROGRAM_ID,
|
||||
@ -304,6 +304,7 @@ fn compute_circuit_output(
|
||||
visibility_mask: &[u8],
|
||||
private_account_keys: &[(NullifierPublicKey, SharedSecretKey)],
|
||||
private_account_nsks: &[NullifierSecretKey],
|
||||
private_account_identifiers: &[Identifier],
|
||||
private_account_membership_proofs: &[Option<MembershipProof>],
|
||||
) -> PrivacyPreservingCircuitOutput {
|
||||
let mut output = PrivacyPreservingCircuitOutput {
|
||||
@ -326,6 +327,7 @@ fn compute_circuit_output(
|
||||
let mut private_keys_iter = private_account_keys.iter();
|
||||
let mut private_nsks_iter = private_account_nsks.iter();
|
||||
let mut private_membership_proofs_iter = private_account_membership_proofs.iter();
|
||||
let mut private_identifiers_iter = private_account_identifiers.iter();
|
||||
|
||||
let mut output_index = 0;
|
||||
for (account_visibility_mask, (pre_state, post_state)) in
|
||||
@ -342,8 +344,12 @@ fn compute_circuit_output(
|
||||
panic!("Missing private account key");
|
||||
};
|
||||
|
||||
let Some(identifier) = private_identifiers_iter.next() else {
|
||||
panic!("Missing private account identifier");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
AccountId::from(npk),
|
||||
AccountId::private_account_id(npk, *identifier),
|
||||
pre_state.account_id,
|
||||
"AccountId mismatch"
|
||||
);
|
||||
@ -371,11 +377,11 @@ fn compute_circuit_output(
|
||||
let Some(membership_proof_opt) = private_membership_proofs_iter.next() else {
|
||||
panic!("Missing membership proof");
|
||||
};
|
||||
|
||||
// TODO: here is the issue
|
||||
let new_nullifier = compute_nullifier_and_set_digest(
|
||||
membership_proof_opt.as_ref(),
|
||||
&pre_state.account,
|
||||
npk,
|
||||
&pre_state.account_id,
|
||||
nsk,
|
||||
);
|
||||
|
||||
@ -405,7 +411,8 @@ fn compute_circuit_output(
|
||||
"Membership proof must be None for unauthorized accounts"
|
||||
);
|
||||
|
||||
let nullifier = Nullifier::for_account_initialization(npk);
|
||||
let account_id = AccountId::private_account_id(npk, *identifier);
|
||||
let nullifier = Nullifier::for_account_initialization(&account_id);
|
||||
|
||||
let new_nonce = Nonce::private_account_nonce_init(npk);
|
||||
|
||||
@ -418,7 +425,8 @@ fn compute_circuit_output(
|
||||
post_with_updated_nonce.nonce = new_nonce;
|
||||
|
||||
// Compute commitment
|
||||
let commitment_post = Commitment::new(npk, &post_with_updated_nonce);
|
||||
let commitment_post =
|
||||
Commitment::new(&pre_state.account_id, &post_with_updated_nonce);
|
||||
|
||||
// Encrypt and push post state
|
||||
let encrypted_account = EncryptionScheme::encrypt(
|
||||
@ -456,10 +464,11 @@ fn compute_circuit_output(
|
||||
output
|
||||
}
|
||||
|
||||
// Marvin: todo
|
||||
fn compute_nullifier_and_set_digest(
|
||||
membership_proof_opt: Option<&MembershipProof>,
|
||||
pre_account: &Account,
|
||||
npk: &NullifierPublicKey,
|
||||
account_id: &AccountId,
|
||||
nsk: &NullifierSecretKey,
|
||||
) -> (Nullifier, CommitmentSetDigest) {
|
||||
membership_proof_opt.as_ref().map_or_else(
|
||||
@ -467,16 +476,16 @@ fn compute_nullifier_and_set_digest(
|
||||
assert_eq!(
|
||||
*pre_account,
|
||||
Account::default(),
|
||||
"Found new private account with non default values"
|
||||
"Found new private account with non default values$Marvin$"
|
||||
);
|
||||
|
||||
// Compute initialization nullifier
|
||||
let nullifier = Nullifier::for_account_initialization(npk);
|
||||
let nullifier = Nullifier::for_account_initialization(account_id);
|
||||
(nullifier, DUMMY_COMMITMENT_HASH)
|
||||
},
|
||||
|membership_proof| {
|
||||
// Compute commitment set digest associated with provided auth path
|
||||
let commitment_pre = Commitment::new(npk, pre_account);
|
||||
let commitment_pre = Commitment::new(account_id, pre_account);
|
||||
let set_digest = compute_digest_for_path(&commitment_pre, membership_proof);
|
||||
|
||||
// Compute update nullifier
|
||||
@ -492,6 +501,7 @@ fn main() {
|
||||
visibility_mask,
|
||||
private_account_keys,
|
||||
private_account_nsks,
|
||||
private_account_identifiers,
|
||||
private_account_membership_proofs,
|
||||
program_id,
|
||||
} = env::read();
|
||||
@ -504,6 +514,7 @@ fn main() {
|
||||
&visibility_mask,
|
||||
&private_account_keys,
|
||||
&private_account_nsks,
|
||||
&private_account_identifiers,
|
||||
&private_account_membership_proofs,
|
||||
);
|
||||
|
||||
|
||||
@ -4,10 +4,9 @@ use amm_core::{
|
||||
PoolDefinition, compute_liquidity_token_pda, compute_liquidity_token_pda_seed,
|
||||
compute_pool_pda, compute_vault_pda, compute_vault_pda_seed,
|
||||
};
|
||||
use nssa::{
|
||||
PrivateKey, PublicKey, PublicTransaction, V03State, program::Program, public_transaction,
|
||||
};
|
||||
use nssa::{PublicTransaction, V03State, program::Program, public_transaction};
|
||||
use nssa_core::{
|
||||
PrivateKey, PublicKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Data},
|
||||
program::{ChainedCall, ProgramId},
|
||||
};
|
||||
@ -1314,19 +1313,19 @@ impl IdForExeTests {
|
||||
}
|
||||
|
||||
fn user_token_a_id() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(
|
||||
&PrivateKeysForTests::user_token_a_key(),
|
||||
))
|
||||
}
|
||||
|
||||
fn user_token_b_id() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(
|
||||
&PrivateKeysForTests::user_token_b_key(),
|
||||
))
|
||||
}
|
||||
|
||||
fn user_token_lp_id() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(
|
||||
&PrivateKeysForTests::user_token_lp_key(),
|
||||
))
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ pub struct SequencerStore {
|
||||
// TODO: Consider adding the hashmap to the database for faster recovery.
|
||||
tx_hash_to_block_map: HashMap<HashType, u64>,
|
||||
genesis_id: u64,
|
||||
signing_key: nssa::PrivateKey,
|
||||
signing_key: nssa_core::PrivateKey,
|
||||
}
|
||||
|
||||
impl SequencerStore {
|
||||
@ -26,7 +26,7 @@ impl SequencerStore {
|
||||
location: &Path,
|
||||
genesis_block: &Block,
|
||||
genesis_msg_id: MantleMsgId,
|
||||
signing_key: nssa::PrivateKey,
|
||||
signing_key: nssa_core::PrivateKey,
|
||||
) -> Result<Self> {
|
||||
let tx_hash_to_block_map = block_to_transactions_map(genesis_block);
|
||||
|
||||
@ -80,7 +80,7 @@ impl SequencerStore {
|
||||
self.genesis_id
|
||||
}
|
||||
|
||||
pub const fn signing_key(&self) -> &nssa::PrivateKey {
|
||||
pub const fn signing_key(&self) -> &nssa_core::PrivateKey {
|
||||
&self.signing_key
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,8 @@ use logos_blockchain_key_management_system_service::keys::{ED25519_SECRET_KEY_SI
|
||||
use mempool::{MemPool, MemPoolHandle};
|
||||
#[cfg(feature = "mock")]
|
||||
pub use mock::SequencerCoreWithMockClients;
|
||||
use nssa::V03State;
|
||||
use nssa::{AccountId, V03State};
|
||||
use nssa_core::account::Identifier;
|
||||
pub use storage::error::DbError;
|
||||
use testnet_initial_state::initial_state;
|
||||
|
||||
@ -62,7 +63,7 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
|
||||
timestamp: 0,
|
||||
};
|
||||
|
||||
let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap();
|
||||
let signing_key = nssa_core::PrivateKey::try_new(config.signing_key).unwrap();
|
||||
let genesis_parent_msg_id = [0; 32];
|
||||
let genesis_block = hashable_data.into_pending_block(&signing_key, genesis_parent_msg_id);
|
||||
|
||||
@ -113,11 +114,11 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
|
||||
let npk = &init_comm_data.npk;
|
||||
|
||||
let mut acc = init_comm_data.account.clone();
|
||||
|
||||
let acc_id = &AccountId::private_account_id(npk, Identifier(0_u128)); //TODO marvin
|
||||
acc.program_owner =
|
||||
nssa::program::Program::authenticated_transfer_program().id();
|
||||
|
||||
nssa_core::Commitment::new(npk, &acc)
|
||||
nssa_core::Commitment::new(acc_id, &acc)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
@ -432,11 +433,11 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_signing_key_for_account1() -> nssa::PrivateKey {
|
||||
fn create_signing_key_for_account1() -> nssa_core::PrivateKey {
|
||||
initial_pub_accounts_private_keys()[0].pub_sign_key.clone()
|
||||
}
|
||||
|
||||
fn create_signing_key_for_account2() -> nssa::PrivateKey {
|
||||
fn create_signing_key_for_account2() -> nssa_core::PrivateKey {
|
||||
initial_pub_accounts_private_keys()[1].pub_sign_key.clone()
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ workspace = true
|
||||
[dependencies]
|
||||
common.workspace = true
|
||||
nssa.workspace = true
|
||||
nssa_core.workspace = true
|
||||
|
||||
thiserror.workspace = true
|
||||
borsh.workspace = true
|
||||
|
||||
@ -213,7 +213,8 @@ fn closest_breakpoint_id(block_id: u64) -> u64 {
|
||||
#[expect(clippy::shadow_unrelated, reason = "Fine for tests")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nssa::{AccountId, PublicKey};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::PublicKey;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
@ -222,20 +223,20 @@ mod tests {
|
||||
common::test_utils::produce_dummy_block(1, None, vec![])
|
||||
}
|
||||
|
||||
fn acc1_sign_key() -> nssa::PrivateKey {
|
||||
nssa::PrivateKey::try_new([1; 32]).unwrap()
|
||||
fn acc1_sign_key() -> nssa_core::PrivateKey {
|
||||
nssa_core::PrivateKey::try_new([1; 32]).unwrap()
|
||||
}
|
||||
|
||||
fn acc2_sign_key() -> nssa::PrivateKey {
|
||||
nssa::PrivateKey::try_new([2; 32]).unwrap()
|
||||
fn acc2_sign_key() -> nssa_core::PrivateKey {
|
||||
nssa_core::PrivateKey::try_new([2; 32]).unwrap()
|
||||
}
|
||||
|
||||
fn acc1() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(&acc1_sign_key()))
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(&acc1_sign_key()))
|
||||
}
|
||||
|
||||
fn acc2() -> AccountId {
|
||||
AccountId::from(&PublicKey::new_from_private_key(&acc2_sign_key()))
|
||||
AccountId::public_account_id(&PublicKey::new_from_private_key(&acc2_sign_key()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -3,8 +3,11 @@ use key_protocol::key_management::{
|
||||
KeyChain,
|
||||
secret_holders::{PrivateKeyHolder, SecretSpendingKey},
|
||||
};
|
||||
use nssa::{Account, AccountId, Data, PrivateKey, PublicKey, V03State};
|
||||
use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point};
|
||||
use nssa::{Account, AccountId, Data, V03State};
|
||||
use nssa_core::{
|
||||
NullifierPublicKey, PrivateKey, PublicKey, account::Identifier,
|
||||
encryption::shared_key_derivation::Secp256k1Point,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const PRIVATE_KEY_PUB_ACC_A: [u8; 32] = [
|
||||
@ -75,6 +78,9 @@ const PUB_ACC_B_INITIAL_BALANCE: u128 = 20000;
|
||||
const PRIV_ACC_A_INITIAL_BALANCE: u128 = 10000;
|
||||
const PRIV_ACC_B_INITIAL_BALANCE: u128 = 20000;
|
||||
|
||||
const PRIV_ACC_A_IDENTIFIER: u128 = 13;
|
||||
const PRIV_ACC_B_IDENTIFIER: u128 = 42;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PublicAccountPublicInitialData {
|
||||
pub account_id: AccountId,
|
||||
@ -84,19 +90,21 @@ pub struct PublicAccountPublicInitialData {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PrivateAccountPublicInitialData {
|
||||
pub npk: nssa_core::NullifierPublicKey,
|
||||
pub identifier: Identifier,
|
||||
pub account: nssa_core::account::Account,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PublicAccountPrivateInitialData {
|
||||
pub account_id: nssa::AccountId,
|
||||
pub pub_sign_key: nssa::PrivateKey,
|
||||
pub pub_sign_key: nssa_core::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PrivateAccountPrivateInitialData {
|
||||
pub account_id: nssa::AccountId,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub identifier: Identifier,
|
||||
pub key_chain: KeyChain,
|
||||
}
|
||||
|
||||
@ -108,11 +116,15 @@ pub fn initial_pub_accounts_private_keys() -> Vec<PublicAccountPrivateInitialDat
|
||||
|
||||
vec![
|
||||
PublicAccountPrivateInitialData {
|
||||
account_id: AccountId::from(&PublicKey::new_from_private_key(&acc1_pub_sign_key)),
|
||||
account_id: AccountId::public_account_id(&PublicKey::new_from_private_key(
|
||||
&acc1_pub_sign_key,
|
||||
)),
|
||||
pub_sign_key: acc1_pub_sign_key,
|
||||
},
|
||||
PublicAccountPrivateInitialData {
|
||||
account_id: AccountId::from(&PublicKey::new_from_private_key(&acc2_pub_sign_key)),
|
||||
account_id: AccountId::public_account_id(&PublicKey::new_from_private_key(
|
||||
&acc2_pub_sign_key,
|
||||
)),
|
||||
pub_sign_key: acc2_pub_sign_key,
|
||||
},
|
||||
]
|
||||
@ -140,25 +152,36 @@ pub fn initial_priv_accounts_private_keys() -> Vec<PrivateAccountPrivateInitialD
|
||||
viewing_public_key: Secp256k1Point(VPK_PRIV_ACC_B.to_vec()),
|
||||
};
|
||||
|
||||
let identifier_1 = Identifier(PRIV_ACC_A_IDENTIFIER);
|
||||
let identifier_2 = Identifier(PRIV_ACC_B_IDENTIFIER);
|
||||
|
||||
vec![
|
||||
PrivateAccountPrivateInitialData {
|
||||
account_id: AccountId::from(&key_chain_1.nullifier_public_key),
|
||||
account_id: AccountId::private_account_id(
|
||||
&key_chain_1.nullifier_public_key,
|
||||
Identifier(13_u128),
|
||||
),
|
||||
account: Account {
|
||||
program_owner: DEFAULT_PROGRAM_OWNER,
|
||||
balance: PRIV_ACC_A_INITIAL_BALANCE,
|
||||
data: Data::default(),
|
||||
nonce: 0.into(),
|
||||
},
|
||||
identifier: identifier_1,
|
||||
key_chain: key_chain_1,
|
||||
},
|
||||
PrivateAccountPrivateInitialData {
|
||||
account_id: AccountId::from(&key_chain_2.nullifier_public_key),
|
||||
account_id: AccountId::private_account_id(
|
||||
&key_chain_2.nullifier_public_key,
|
||||
Identifier(42_u128),
|
||||
),
|
||||
account: Account {
|
||||
program_owner: DEFAULT_PROGRAM_OWNER,
|
||||
balance: PRIV_ACC_B_INITIAL_BALANCE,
|
||||
data: Data::default(),
|
||||
nonce: 0.into(),
|
||||
},
|
||||
identifier: identifier_2,
|
||||
key_chain: key_chain_2,
|
||||
},
|
||||
]
|
||||
@ -170,6 +193,7 @@ pub fn initial_commitments() -> Vec<PrivateAccountPublicInitialData> {
|
||||
.into_iter()
|
||||
.map(|data| PrivateAccountPublicInitialData {
|
||||
npk: data.key_chain.nullifier_public_key.clone(),
|
||||
identifier: data.identifier,
|
||||
account: data.account,
|
||||
})
|
||||
.collect()
|
||||
@ -199,13 +223,14 @@ pub fn initial_state() -> V03State {
|
||||
let initial_commitments: Vec<nssa_core::Commitment> = initial_commitments()
|
||||
.iter()
|
||||
.map(|init_comm_data| {
|
||||
let npk = &init_comm_data.npk;
|
||||
let acc_id =
|
||||
&AccountId::private_account_id(&init_comm_data.npk, init_comm_data.identifier);
|
||||
|
||||
let mut acc = init_comm_data.account.clone();
|
||||
|
||||
acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
|
||||
nssa_core::Commitment::new(npk, &acc)
|
||||
nssa_core::Commitment::new(acc_id, &acc)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -371,6 +396,7 @@ mod tests {
|
||||
init_comms[0],
|
||||
PrivateAccountPublicInitialData {
|
||||
npk: NullifierPublicKey(NPK_PRIV_ACC_A),
|
||||
identifier: Identifier(PRIV_ACC_A_IDENTIFIER),
|
||||
account: Account {
|
||||
program_owner: DEFAULT_PROGRAM_OWNER,
|
||||
balance: PRIV_ACC_A_INITIAL_BALANCE,
|
||||
@ -384,6 +410,7 @@ mod tests {
|
||||
init_comms[1],
|
||||
PrivateAccountPublicInitialData {
|
||||
npk: NullifierPublicKey(NPK_PRIV_ACC_B),
|
||||
identifier: Identifier(PRIV_ACC_B_IDENTIFIER),
|
||||
account: Account {
|
||||
program_owner: DEFAULT_PROGRAM_OWNER,
|
||||
balance: PRIV_ACC_B_INITIAL_BALANCE,
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use nssa::{AccountId, PublicKey};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::PublicKey;
|
||||
|
||||
use crate::{
|
||||
error::{print_error, WalletFfiError},
|
||||
|
||||
@ -249,15 +249,15 @@ impl TryFrom<&FfiAccount> for nssa::Account {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nssa::PublicKey> for FfiPublicAccountKey {
|
||||
fn from(value: nssa::PublicKey) -> Self {
|
||||
impl From<nssa_core::PublicKey> for FfiPublicAccountKey {
|
||||
fn from(value: nssa_core::PublicKey) -> Self {
|
||||
Self {
|
||||
public_key: FfiBytes32::from_bytes(*value.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&FfiPublicAccountKey> for nssa::PublicKey {
|
||||
impl TryFrom<&FfiPublicAccountKey> for nssa_core::PublicKey {
|
||||
type Error = WalletFfiError;
|
||||
|
||||
fn try_from(value: &FfiPublicAccountKey) -> Result<Self, Self::Error> {
|
||||
|
||||
@ -86,6 +86,7 @@ impl WalletChainStore {
|
||||
data.account_id,
|
||||
PrivateBundle {
|
||||
key_chain: data.key_chain,
|
||||
identifier: data.identifier,
|
||||
account: data.account,
|
||||
},
|
||||
);
|
||||
@ -136,6 +137,7 @@ impl WalletChainStore {
|
||||
data.account_id,
|
||||
PrivateBundle {
|
||||
key_chain: data.key_chain,
|
||||
identifier: data.identifier,
|
||||
account,
|
||||
},
|
||||
);
|
||||
@ -211,7 +213,7 @@ impl WalletChainStore {
|
||||
.private_key_tree
|
||||
.key_map
|
||||
.entry(chain_index.clone())
|
||||
.and_modify(|data| data.value.1 = account)
|
||||
.and_modify(|data| data.value.account = account)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,8 @@ use anyhow::{Context as _, Result};
|
||||
use clap::Subcommand;
|
||||
use itertools::Itertools as _;
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use nssa::{Account, PublicKey, program::Program};
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa_core::PublicKey;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
|
||||
@ -193,6 +193,7 @@ pub fn produce_data_for_storage(
|
||||
InitialAccountData::Private(Box::new(PrivateAccountPrivateInitialData {
|
||||
account_id: *account_id,
|
||||
account: bundle.account.clone(),
|
||||
identifier: bundle.identifier,
|
||||
key_chain: bundle.key_chain.clone(),
|
||||
}))
|
||||
.into(),
|
||||
|
||||
@ -287,7 +287,7 @@ impl WalletCore {
|
||||
pub fn get_account_public_signing_key(
|
||||
&self,
|
||||
account_id: AccountId,
|
||||
) -> Option<&nssa::PrivateKey> {
|
||||
) -> Option<&nssa_core::PrivateKey> {
|
||||
self.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(account_id)
|
||||
@ -305,7 +305,10 @@ impl WalletCore {
|
||||
pub fn get_private_account_commitment(&self, account_id: AccountId) -> Option<Commitment> {
|
||||
let bundle = self.storage.user_data.get_private_account(account_id)?;
|
||||
Some(Commitment::new(
|
||||
&bundle.key_chain.nullifier_public_key,
|
||||
&AccountId::private_account_id(
|
||||
&bundle.key_chain.nullifier_public_key,
|
||||
bundle.identifier,
|
||||
),
|
||||
&bundle.account,
|
||||
))
|
||||
}
|
||||
@ -393,6 +396,12 @@ impl WalletCore {
|
||||
)?;
|
||||
|
||||
let private_account_keys = acc_manager.private_account_keys();
|
||||
let private_account_identifiers =
|
||||
acc_manager.private_account_identifiers(&private_account_keys);
|
||||
// TODO: here. This is the function I want to use
|
||||
// Okay. Now I have the "corrected" identifiers but NOT correct account_ids! (Marvin)
|
||||
// -> So, we need to update AccountIds with these identifiers
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
pre_states,
|
||||
instruction_data,
|
||||
@ -402,6 +411,7 @@ impl WalletCore {
|
||||
.map(|keys| (keys.npk.clone(), keys.ssk))
|
||||
.collect::<Vec<_>>(),
|
||||
acc_manager.private_account_auth(),
|
||||
private_account_identifiers.clone(), // TODO: when was this done? Marvin
|
||||
acc_manager.private_account_membership_proofs(),
|
||||
&program.to_owned(),
|
||||
)
|
||||
@ -413,7 +423,14 @@ impl WalletCore {
|
||||
Vec::from_iter(acc_manager.public_account_nonces()),
|
||||
private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk.clone(), keys.vpk.clone(), keys.epk.clone()))
|
||||
.zip(private_account_identifiers)
|
||||
.map(|(keys, identifier)| {
|
||||
(
|
||||
AccountId::private_account_id(&keys.npk.clone(), identifier),
|
||||
keys.vpk.clone(),
|
||||
keys.epk.clone(),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
output,
|
||||
)
|
||||
@ -495,6 +512,7 @@ impl WalletCore {
|
||||
acc_account_id,
|
||||
PrivateBundle {
|
||||
key_chain,
|
||||
identifier: _,
|
||||
account: _,
|
||||
},
|
||||
)| (*acc_account_id, key_chain, None),
|
||||
@ -503,7 +521,7 @@ impl WalletCore {
|
||||
|(chain_index, keys_node)| {
|
||||
(
|
||||
keys_node.account_id(),
|
||||
&keys_node.value.0,
|
||||
&keys_node.value.key_chain,
|
||||
chain_index.index(),
|
||||
)
|
||||
},
|
||||
@ -511,8 +529,9 @@ impl WalletCore {
|
||||
|
||||
let affected_accounts = private_account_key_chains
|
||||
.flat_map(|(acc_account_id, key_chain, index)| {
|
||||
// Why index? Marvin
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
&key_chain.nullifier_public_key,
|
||||
&acc_account_id,
|
||||
&key_chain.viewing_public_key,
|
||||
);
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{AccountId, PrivateKey};
|
||||
use nssa::AccountId;
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||
account::{AccountWithMetadata, Nonce},
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivateKey, SharedSecretKey,
|
||||
account::{AccountWithMetadata, Identifier, Nonce},
|
||||
encryption::{EphemeralPublicKey, ViewingPublicKey},
|
||||
};
|
||||
|
||||
@ -81,10 +81,13 @@ impl AccountManager {
|
||||
|
||||
(State::Private(pre), mask)
|
||||
}
|
||||
|
||||
PrivacyPreservingAccount::PrivateForeign { npk, vpk } => {
|
||||
let account_id = AccountId::private_account_id(&npk, Identifier::default()); //Okay. This is being used a flag currently (Marvin) trying something
|
||||
let acc = nssa_core::account::Account::default();
|
||||
let auth_acc = AccountWithMetadata::new(acc, false, &npk);
|
||||
let auth_acc = AccountWithMetadata::new(acc, false, account_id);
|
||||
let pre = AccountPreparedData {
|
||||
identifier: Identifier::default(), // TODO: ugh. Marvin
|
||||
nsk: None,
|
||||
npk,
|
||||
vpk,
|
||||
@ -136,12 +139,13 @@ impl AccountManager {
|
||||
.filter_map(|state| match state {
|
||||
State::Private(pre) => {
|
||||
let eph_holder = EphemeralKeyHolder::new(&pre.npk);
|
||||
let epk = eph_holder.generate_ephemeral_public_key();
|
||||
|
||||
Some(PrivateAccountKeys {
|
||||
npk: pre.npk.clone(),
|
||||
ssk: eph_holder.calculate_shared_secret_sender(&pre.vpk),
|
||||
vpk: pre.vpk.clone(),
|
||||
epk: eph_holder.generate_ephemeral_public_key(),
|
||||
epk,
|
||||
})
|
||||
}
|
||||
State::Public { .. } => None,
|
||||
@ -149,6 +153,27 @@ impl AccountManager {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn private_account_identifiers(
|
||||
&self,
|
||||
private_account_keys: &Vec<PrivateAccountKeys>,
|
||||
) -> Vec<Identifier> {
|
||||
self.states
|
||||
.iter()
|
||||
.zip(private_account_keys)
|
||||
.filter_map(|(state, key)| match state {
|
||||
State::Private(pre) => {
|
||||
if pre.identifier == Identifier::default() {
|
||||
// Some(Identifier::default()) ATA works here ATA issue (Marvin)
|
||||
Some(Identifier::private_identifier(&key.epk, 0)) //TODO: currently using a placeholder index (Marvin)
|
||||
} else {
|
||||
Some(pre.identifier)
|
||||
}
|
||||
}
|
||||
State::Public { .. } => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn private_account_auth(&self) -> Vec<NullifierSecretKey> {
|
||||
self.states
|
||||
.iter()
|
||||
@ -191,6 +216,7 @@ impl AccountManager {
|
||||
}
|
||||
|
||||
struct AccountPreparedData {
|
||||
identifier: Identifier,
|
||||
nsk: Option<NullifierSecretKey>,
|
||||
npk: NullifierPublicKey,
|
||||
vpk: ViewingPublicKey,
|
||||
@ -208,6 +234,7 @@ async fn private_acc_preparation(
|
||||
|
||||
let from_keys = from_bundle.key_chain;
|
||||
let from_acc = from_bundle.account;
|
||||
let from_identifier = from_bundle.identifier;
|
||||
|
||||
let nsk = from_keys.private_key_holder.nullifier_secret_key;
|
||||
|
||||
@ -222,9 +249,10 @@ async fn private_acc_preparation(
|
||||
|
||||
// TODO: Technically we could allow unauthorized owned accounts, but currently we don't have
|
||||
// support from that in the wallet.
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
|
||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, account_id);
|
||||
|
||||
Ok(AccountPreparedData {
|
||||
identifier: from_identifier,
|
||||
nsk: Some(nsk),
|
||||
npk: from_npk,
|
||||
vpk: from_vpk,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user