chore: update to release set v0.2.1

This commit is contained in:
r4bbit
2026-08-25 12:49:19 +02:00
parent 3994ba3055
commit 730053dcc7
63 changed files with 25164 additions and 12571 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ workspace = true
[dependencies]
nssa = { workspace = true }
nssa_core = { workspace = true, features = ["host", "test_utils"] }
clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0" }
clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.2" }
amm_core = { workspace = true }
token_core = { workspace = true }
ata_core = { workspace = true }
+6
View File
@@ -1885,6 +1885,12 @@ fn advance_clock(state: &mut V03State, timestamp: u64) {
}
.to_bytes();
let clock_account = Account {
// The real CLOCK_01 system account is owned by the clock program, not the
// default program (see lee `system_accounts::clock_account`). A default owner
// makes the spel-framework output filter drop the (unchanged, unclaimed)
// clock post-state, which v0.2.1's DeclaredAccountMissingFromOutput invariant
// then rejects. Use a non-default placeholder owner, as the oracle fixtures do.
program_owner: [8u32; 8],
data: Data::try_from(data).expect("clock account data fits"),
..Account::default()
};
+13 -17
View File
@@ -8,12 +8,12 @@ use nssa::{
},
program::Program,
program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey, V03State,
public_transaction, PrivateKey, PublicKey, PublicTransaction, V03State,
};
use nssa_core::{
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
encryption::{EphemeralPublicKey, ViewingPublicKey},
EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey,
encryption::ViewingPublicKey,
InputAccountIdentity, NullifierPublicKey, NullifierSecretKey,
};
use token_core::{TokenDefinition, TokenHolding};
@@ -515,14 +515,14 @@ fn ata_create_from_private_owner() {
let owner_npk = NullifierPublicKey::from(&owner_nsk);
// `ViewingPublicKey::from_seed` needs two 32-byte halves `(d, z)`.
let owner_vpk = ViewingPublicKey::from_seed(&[31u8; 32], &[32u8; 32]);
let owner_id = AccountId::for_regular_private_account(&owner_npk, 0);
let owner_id = AccountId::for_regular_private_account(&owner_npk, &owner_vpk, 0);
// ATA derived from the private owner
let seed = compute_ata_seed(Ids::token_program(), owner_id, Ids::token_definition());
let owner_ata_id = get_associated_token_account_id(&Ids::ata_program(), &seed);
// Pre-states: private uninitialized owner, public token definition, public uninitialized ATA.
let owner_pre = AccountWithMetadata::new(Account::default(), false, owner_id);
let owner_pre = AccountWithMetadata::new(Account::default(), true, owner_id);
let def_pre = AccountWithMetadata::new(
Accounts::token_definition_init(),
false,
@@ -535,8 +535,9 @@ fn ata_create_from_private_owner() {
};
let instruction_data = Program::serialize_instruction(instruction).unwrap();
// Encapsulate a shared secret against the owner's viewing key; the circuit fills the EPK.
let shared_secret = SharedSecretKey::encapsulate_deterministic(&owner_vpk, &[0u8; 32], 0).0;
// The private owner is a fresh account the caller does not own: PrivateForeignInit.
// The circuit derives the EPK from `random_seed`; the init references the current root.
let commitment_root = state.commitment_root();
let ata_program = Program::new(ata_methods::ATA_ELF.to_vec().into()).unwrap();
let token_program = Program::new(token_methods::TOKEN_ELF.to_vec().into()).unwrap();
@@ -550,12 +551,12 @@ fn ata_create_from_private_owner() {
instruction_data,
vec![
// owner: new private account, not owned/spent by the caller (no nsk, no proof).
InputAccountIdentity::PrivateUnauthorized {
epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(&owner_npk, &owner_vpk),
InputAccountIdentity::PrivateForeignInit {
vpk: owner_vpk,
random_seed: [0; 32],
npk: owner_npk,
ssk: shared_secret,
identifier: 0,
commitment_root,
},
// token_definition: public
InputAccountIdentity::Public,
@@ -566,12 +567,7 @@ fn ata_create_from_private_owner() {
)
.unwrap();
let message = Message::try_from_circuit_output(
vec![Ids::token_definition(), owner_ata_id],
vec![],
output,
)
.unwrap();
let message = Message::from_circuit_output(vec![], output);
let witness_set = WitnessSet::for_message(&message, proof, &[]);
let tx = PrivacyPreservingTransaction::new(message, witness_set);
@@ -226,6 +226,12 @@ fn seed_clock(state: &mut V03State, timestamp: u64) {
}
.to_bytes();
let clock_account = Account {
// The real CLOCK_01 system account is owned by the clock program, not the
// default program (see lee `system_accounts::clock_account`). A default owner
// makes the spel-framework output filter drop the (unchanged, unclaimed)
// clock post-state, which v0.2.1's DeclaredAccountMissingFromOutput invariant
// then rejects. Use a non-default placeholder owner, as the oracle fixture does.
program_owner: [8u32; 8],
data: Data::try_from(data).expect("clock account data fits"),
..Account::default()
};
@@ -258,6 +264,21 @@ fn state_for_stablecoin_tests() -> V03State {
Accounts::collateral_definition_init(),
);
state.force_insert_account(Ids::user_holding(), Accounts::user_holding_init());
// Seed the owner as a non-default-owned account. In nssa, balance-holding user
// accounts are owned by a system program (see lee `system_accounts` / the
// `time_locked_transfer` sender), not the default program. A default-owned owner
// works the first time it signs (its pre-state is still `Account::default()`), but
// once `open_position` bumps its nonce the spel-framework output filter drops the
// (unchanged, unclaimed, default-owned) owner post-state from the second
// transaction — which v0.2.1's DeclaredAccountMissingFromOutput invariant then
// rejects. A non-default owner keeps it in the diff across both transactions.
state.force_insert_account(
Ids::owner(),
Account {
program_owner: [7u32; 8],
..Account::default()
},
);
state
}
+29 -41
View File
@@ -3,12 +3,12 @@ use nssa::{
privacy_preserving_transaction::{Message, PrivacyPreservingTransaction, WitnessSet},
program::Program,
program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey, V03State,
public_transaction, PrivateKey, PublicKey, PublicTransaction, V03State,
};
use nssa_core::{
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
encryption::{EphemeralPublicKey, ViewingPublicKey},
Commitment, EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey,
encryption::ViewingPublicKey,
Commitment, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey,
};
use token_core::{TokenDefinition, TokenHolding};
@@ -648,7 +648,7 @@ impl PrivateKeys {
}
fn holder_id() -> AccountId {
AccountId::for_regular_private_account(&Self::holder_npk(), 0)
AccountId::for_regular_private_account(&Self::holder_npk(), &Self::holder_vpk(), 0)
}
fn recipient_nsk() -> NullifierSecretKey {
@@ -664,7 +664,7 @@ impl PrivateKeys {
}
fn recipient_id() -> AccountId {
AccountId::for_regular_private_account(&Self::recipient_npk(), 0)
AccountId::for_regular_private_account(&Self::recipient_npk(), &Self::recipient_vpk(), 0)
}
}
@@ -686,11 +686,12 @@ fn shielded_token_transfer(amount: u128, state: &mut V03State) -> Account {
let recipient_id = PrivateKeys::recipient_id();
let sender = AccountWithMetadata::new(sender_account, true, sender_id);
let recipient = AccountWithMetadata::new(Account::default(), false, recipient_id);
let recipient = AccountWithMetadata::new(Account::default(), true, recipient_id);
// Sender encapsulates a shared secret against the recipient's viewing key. The
// circuit fills the real EPK, so we pass an empty placeholder in the identity.
let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0;
// The recipient is a fresh private account the sender does not own: PrivateForeignInit.
// The circuit derives the EPK from `random_seed`; the init references the current
// commitment-set root.
let commitment_root = state.commitment_root();
let instruction = token_core::Instruction::Transfer {
amount_to_transfer: amount,
@@ -700,20 +701,19 @@ fn shielded_token_transfer(amount: u128, state: &mut V03State) -> Account {
Program::serialize_instruction(instruction).unwrap(),
vec![
InputAccountIdentity::Public,
InputAccountIdentity::PrivateUnauthorized {
epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk),
InputAccountIdentity::PrivateForeignInit {
vpk: recipient_vpk,
random_seed: [0; 32],
npk: recipient_npk,
ssk: shared_secret,
identifier: 0,
commitment_root,
},
],
&token_program().into(),
)
.unwrap();
let message =
Message::try_from_circuit_output(vec![sender_id], vec![sender_nonce], output).unwrap();
let message = Message::from_circuit_output(vec![sender_nonce], output);
let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::holder_key()]);
let tx = PrivacyPreservingTransaction::new(message, witness_set);
@@ -766,7 +766,6 @@ fn token_private_transfer() {
// Shield tokens into a private account (becomes the sender for the private transfer).
let sender_account = shielded_token_transfer(shielded_amount, &mut state);
let sender_npk = PrivateKeys::recipient_npk();
let sender_nsk = PrivateKeys::recipient_nsk();
let sender_vpk = PrivateKeys::recipient_vpk();
let sender_id = PrivateKeys::recipient_id();
@@ -779,14 +778,10 @@ fn token_private_transfer() {
let membership_proof = state
.get_proof_for_commitment(&sender_commitment)
.expect("sender's commitment must be in the set");
// Distinct `output_index` per private output keeps the encapsulated secrets reproducible.
let shared_secret_1 = SharedSecretKey::encapsulate_deterministic(&sender_vpk, &[0u8; 32], 0).0;
let shared_secret_2 =
SharedSecretKey::encapsulate_deterministic(&new_recipient_vpk, &[0u8; 32], 1).0;
let commitment_root = state.commitment_root();
let sender_pre = AccountWithMetadata::new(sender_account.clone(), true, sender_id);
let new_recipient_pre = AccountWithMetadata::new(Account::default(), false, new_recipient_id);
let new_recipient_pre = AccountWithMetadata::new(Account::default(), true, new_recipient_id);
let instruction = token_core::Instruction::Transfer {
amount_to_transfer: transfer_amount,
@@ -796,29 +791,26 @@ fn token_private_transfer() {
Program::serialize_instruction(instruction).unwrap(),
vec![
InputAccountIdentity::PrivateAuthorizedUpdate {
epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(&sender_npk, &sender_vpk),
ssk: shared_secret_1,
vpk: sender_vpk,
random_seed: [0; 32],
view_tag: 0,
nsk: sender_nsk,
membership_proof,
identifier: 0,
},
InputAccountIdentity::PrivateUnauthorized {
epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(
&new_recipient_npk,
&new_recipient_vpk,
),
InputAccountIdentity::PrivateForeignInit {
vpk: new_recipient_vpk,
random_seed: [0; 32],
npk: new_recipient_npk,
ssk: shared_secret_2,
identifier: 0,
commitment_root,
},
],
&token_program().into(),
)
.unwrap();
let message = Message::try_from_circuit_output(vec![], vec![], output).unwrap();
let message = Message::from_circuit_output(vec![], output);
let witness_set = WitnessSet::for_message(&message, proof, &[]);
let tx = PrivacyPreservingTransaction::new(message, witness_set);
@@ -863,7 +855,6 @@ fn token_deshielded_transfer() {
// Shield tokens into a private account, then deshield some back to a public account.
let sender_account = shielded_token_transfer(shielded_amount, &mut state);
let sender_npk = PrivateKeys::recipient_npk();
let sender_nsk = PrivateKeys::recipient_nsk();
let sender_vpk = PrivateKeys::recipient_vpk();
let sender_id = PrivateKeys::recipient_id();
@@ -874,8 +865,6 @@ fn token_deshielded_transfer() {
.get_proof_for_commitment(&sender_commitment)
.expect("sender's commitment must be in the set");
let shared_secret = SharedSecretKey::encapsulate_deterministic(&sender_vpk, &[0u8; 32], 0).0;
let public_recipient_pre = AccountWithMetadata::new(
state.get_account_by_id(public_recipient_id),
false,
@@ -891,9 +880,9 @@ fn token_deshielded_transfer() {
Program::serialize_instruction(instruction).unwrap(),
vec![
InputAccountIdentity::PrivateAuthorizedUpdate {
epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(&sender_npk, &sender_vpk),
ssk: shared_secret,
vpk: sender_vpk,
random_seed: [0; 32],
view_tag: 0,
nsk: sender_nsk,
membership_proof,
identifier: 0,
@@ -904,8 +893,7 @@ fn token_deshielded_transfer() {
)
.unwrap();
let message =
Message::try_from_circuit_output(vec![public_recipient_id], vec![], output).unwrap();
let message = Message::from_circuit_output(vec![], output);
let witness_set = WitnessSet::for_message(&message, proof, &[]);
let tx = PrivacyPreservingTransaction::new(message, witness_set);