mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 21:33:09 +00:00
Merge pull request #166 from vacp2p/Pravdyvy/iss131-error-handling
Borsh derivation in place of previous manual encodings
This commit is contained in:
commit
a99aec05eb
@ -12,6 +12,7 @@ chacha20 = { version = "0.9", default-features = false }
|
||||
k256 = { version = "0.13.3", optional = true }
|
||||
base58 = { version = "0.2.0", optional = true }
|
||||
anyhow = { version = "1.0.98", optional = true }
|
||||
borsh.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@ -3,6 +3,7 @@ use std::{fmt::Display, str::FromStr};
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
use base58::{FromBase58, ToBase58};
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::program::ProgramId;
|
||||
@ -11,7 +12,9 @@ pub type Nonce = u128;
|
||||
pub type Data = Vec<u8>;
|
||||
|
||||
/// Account to be used both in public and private contexts
|
||||
#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Clone, Default, PartialEq, Eq, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||
pub struct Account {
|
||||
pub program_owner: ProgramId,
|
||||
@ -39,7 +42,7 @@ impl AccountWithMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(
|
||||
any(feature = "host", test),
|
||||
derive(Debug, Copy, PartialOrd, Ord, Default)
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use risc0_zkvm::sha::{Impl, Sha256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{NullifierPublicKey, account::Account};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq, Hash))]
|
||||
pub struct Commitment(pub(super) [u8; 32]);
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use chacha20::{
|
||||
ChaCha20,
|
||||
cipher::{KeyIvInit, StreamCipher},
|
||||
@ -20,7 +21,7 @@ pub struct SharedSecretKey(pub [u8; 32]);
|
||||
|
||||
pub struct EncryptionScheme;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq))]
|
||||
pub struct Ciphertext(pub(crate) Vec<u8>);
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use k256::{
|
||||
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint,
|
||||
elliptic_curve::{
|
||||
@ -9,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{SharedSecretKey, encryption::Scalar};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Secp256k1Point(pub Vec<u8>);
|
||||
|
||||
impl Secp256k1Point {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use risc0_zkvm::sha::{Impl, Sha256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -40,7 +41,7 @@ impl From<&NullifierSecretKey> for NullifierPublicKey {
|
||||
|
||||
pub type NullifierSecretKey = [u8; 32];
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq, Hash))]
|
||||
pub struct Nullifier(pub(super) [u8; 32]);
|
||||
|
||||
|
||||
1
nssa/program_methods/guest/Cargo.lock
generated
1
nssa/program_methods/guest/Cargo.lock
generated
@ -1574,6 +1574,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
name = "nssa-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"chacha20",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
|
||||
@ -1,258 +1,24 @@
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use nssa_core::{
|
||||
Commitment, Nullifier,
|
||||
account::Account,
|
||||
encryption::{Ciphertext, EphemeralPublicKey},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
AccountId, PrivacyPreservingTransaction, PublicKey, Signature,
|
||||
error::NssaError,
|
||||
privacy_preserving_transaction::{
|
||||
circuit::Proof,
|
||||
message::{EncryptedAccountData, Message},
|
||||
witness_set::WitnessSet,
|
||||
},
|
||||
PrivacyPreservingTransaction, error::NssaError,
|
||||
privacy_preserving_transaction::message::Message,
|
||||
};
|
||||
|
||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||
b"/NSSA/v0.2/TxMessage/Private/\x00\x00\x00";
|
||||
|
||||
impl EncryptedAccountData {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = self.ciphertext.to_bytes();
|
||||
bytes.extend_from_slice(&self.epk.to_bytes());
|
||||
bytes.push(self.view_tag);
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let ciphertext = Ciphertext::from_cursor(cursor)?;
|
||||
let epk = EphemeralPublicKey::from_cursor(cursor)?;
|
||||
|
||||
let mut tag_bytes = [0; 1];
|
||||
cursor.read_exact(&mut tag_bytes)?;
|
||||
let view_tag = tag_bytes[0];
|
||||
|
||||
Ok(Self {
|
||||
ciphertext,
|
||||
epk,
|
||||
view_tag,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||
|
||||
// Public account_ids
|
||||
let public_account_ids_len: u32 = self.public_account_ids.len() as u32;
|
||||
bytes.extend_from_slice(&public_account_ids_len.to_le_bytes());
|
||||
for account_id in &self.public_account_ids {
|
||||
bytes.extend_from_slice(account_id.value());
|
||||
}
|
||||
// Nonces
|
||||
let nonces_len = self.nonces.len() as u32;
|
||||
bytes.extend(&nonces_len.to_le_bytes());
|
||||
for nonce in &self.nonces {
|
||||
bytes.extend(&nonce.to_le_bytes());
|
||||
}
|
||||
// Public post states
|
||||
let public_post_states_len: u32 = self.public_post_states.len() as u32;
|
||||
bytes.extend_from_slice(&public_post_states_len.to_le_bytes());
|
||||
for account in &self.public_post_states {
|
||||
bytes.extend_from_slice(&account.to_bytes());
|
||||
}
|
||||
|
||||
// Encrypted post states
|
||||
let encrypted_accounts_post_states_len: u32 =
|
||||
self.encrypted_private_post_states.len() as u32;
|
||||
bytes.extend_from_slice(&encrypted_accounts_post_states_len.to_le_bytes());
|
||||
for encrypted_account in &self.encrypted_private_post_states {
|
||||
bytes.extend_from_slice(&encrypted_account.to_bytes());
|
||||
}
|
||||
|
||||
// New commitments
|
||||
let new_commitments_len: u32 = self.new_commitments.len() as u32;
|
||||
bytes.extend_from_slice(&new_commitments_len.to_le_bytes());
|
||||
for commitment in &self.new_commitments {
|
||||
bytes.extend_from_slice(&commitment.to_byte_array());
|
||||
}
|
||||
|
||||
// New nullifiers
|
||||
let new_nullifiers_len: u32 = self.new_nullifiers.len() as u32;
|
||||
bytes.extend_from_slice(&new_nullifiers_len.to_le_bytes());
|
||||
for (nullifier, commitment_set_digest) in &self.new_nullifiers {
|
||||
bytes.extend_from_slice(&nullifier.to_byte_array());
|
||||
bytes.extend_from_slice(commitment_set_digest);
|
||||
}
|
||||
|
||||
bytes
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
borsh::to_vec(&self).expect("Autoderived borsh serialization failure")
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let prefix = {
|
||||
let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN];
|
||||
cursor.read_exact(&mut this)?;
|
||||
this
|
||||
};
|
||||
if &prefix != MESSAGE_ENCODING_PREFIX {
|
||||
return Err(NssaError::TransactionDeserializationError(
|
||||
"Invalid privacy preserving message prefix".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut len_bytes = [0u8; 4];
|
||||
|
||||
// Public account_ids
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let public_account_ids_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut public_account_ids = Vec::with_capacity(public_account_ids_len);
|
||||
for _ in 0..public_account_ids_len {
|
||||
let mut value = [0u8; 32];
|
||||
cursor.read_exact(&mut value)?;
|
||||
public_account_ids.push(AccountId::new(value))
|
||||
}
|
||||
|
||||
// Nonces
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let nonces_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut nonces = Vec::with_capacity(nonces_len);
|
||||
for _ in 0..nonces_len {
|
||||
let mut buf = [0u8; 16];
|
||||
cursor.read_exact(&mut buf)?;
|
||||
nonces.push(u128::from_le_bytes(buf))
|
||||
}
|
||||
|
||||
// Public post states
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let public_post_states_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut public_post_states = Vec::with_capacity(public_post_states_len);
|
||||
for _ in 0..public_post_states_len {
|
||||
public_post_states.push(Account::from_cursor(cursor)?);
|
||||
}
|
||||
|
||||
// Encrypted private post states
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let encrypted_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut encrypted_private_post_states = Vec::with_capacity(encrypted_len);
|
||||
for _ in 0..encrypted_len {
|
||||
encrypted_private_post_states.push(EncryptedAccountData::from_cursor(cursor)?);
|
||||
}
|
||||
|
||||
// New commitments
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let new_commitments_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut new_commitments = Vec::with_capacity(new_commitments_len);
|
||||
for _ in 0..new_commitments_len {
|
||||
new_commitments.push(Commitment::from_cursor(cursor)?);
|
||||
}
|
||||
|
||||
// New nullifiers
|
||||
cursor.read_exact(&mut len_bytes)?;
|
||||
let new_nullifiers_len = u32::from_le_bytes(len_bytes) as usize;
|
||||
let mut new_nullifiers = Vec::with_capacity(new_nullifiers_len);
|
||||
for _ in 0..new_nullifiers_len {
|
||||
let nullifier = Nullifier::from_cursor(cursor)?;
|
||||
let mut commitment_set_digest = [0; 32];
|
||||
cursor.read_exact(&mut commitment_set_digest)?;
|
||||
new_nullifiers.push((nullifier, commitment_set_digest));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
public_account_ids,
|
||||
nonces,
|
||||
public_post_states,
|
||||
encrypted_private_post_states,
|
||||
new_commitments,
|
||||
new_nullifiers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WitnessSet {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
let size = self.signatures_and_public_keys().len() as u32;
|
||||
bytes.extend_from_slice(&size.to_le_bytes());
|
||||
for (signature, public_key) in self.signatures_and_public_keys() {
|
||||
bytes.extend_from_slice(signature.to_bytes());
|
||||
bytes.extend_from_slice(public_key.to_bytes());
|
||||
}
|
||||
bytes.extend_from_slice(&self.proof.to_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let num_signatures: u32 = {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf)?;
|
||||
u32::from_le_bytes(buf)
|
||||
};
|
||||
let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize);
|
||||
for _i in 0..num_signatures {
|
||||
let signature = Signature::from_cursor(cursor)?;
|
||||
let public_key = PublicKey::from_cursor(cursor)?;
|
||||
signatures_and_public_keys.push((signature, public_key))
|
||||
}
|
||||
let proof = Proof::from_cursor(cursor)?;
|
||||
Ok(Self {
|
||||
signatures_and_public_keys,
|
||||
proof,
|
||||
})
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
|
||||
Ok(borsh::from_slice(bytes)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrivacyPreservingTransaction {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = self.message().to_bytes();
|
||||
bytes.extend_from_slice(&self.witness_set().to_bytes());
|
||||
bytes
|
||||
borsh::to_vec(&self).expect("Autoderived borsh serialization failure")
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
Self::from_cursor(&mut cursor)
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let message = Message::from_cursor(cursor)?;
|
||||
let witness_set = WitnessSet::from_cursor(cursor)?;
|
||||
Ok(PrivacyPreservingTransaction::new(message, witness_set))
|
||||
Ok(borsh::from_slice(bytes)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
let proof_len = self.0.len() as u32;
|
||||
bytes.extend_from_slice(&proof_len.to_le_bytes());
|
||||
bytes.extend_from_slice(&self.0);
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let proof_len = u32_from_cursor(cursor) as usize;
|
||||
let mut proof = Vec::with_capacity(proof_len);
|
||||
|
||||
for _ in 0..proof_len {
|
||||
let mut one_byte_buf = [0u8];
|
||||
|
||||
cursor.read_exact(&mut one_byte_buf)?;
|
||||
|
||||
proof.push(one_byte_buf[0]);
|
||||
}
|
||||
Ok(Self(proof))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Improve error handling. Remove unwraps.
|
||||
pub fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 {
|
||||
let mut word_buf = [0u8; 4];
|
||||
cursor.read_exact(&mut word_buf).unwrap();
|
||||
u32::from_le_bytes(word_buf)
|
||||
}
|
||||
|
||||
@ -1,77 +1,17 @@
|
||||
// TODO: Consider switching to deriving Borsh
|
||||
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use crate::{
|
||||
ProgramDeploymentTransaction, error::NssaError, program_deployment_transaction::Message,
|
||||
};
|
||||
|
||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||
b"/NSSA/v0.2/TxMessage/Program/\x00\x00\x00";
|
||||
|
||||
impl Message {
|
||||
/// Serializes a `Message` into bytes in the following layout:
|
||||
/// PREFIX || bytecode_len (4 bytes LE) || <bytecode>
|
||||
/// Integers are encoded in little-endian byte order, and fields appear in the above order.
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||
let bytecode_len = self.bytecode.len() as u32;
|
||||
bytes.extend(&bytecode_len.to_le_bytes());
|
||||
bytes.extend(&self.bytecode);
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let prefix = {
|
||||
let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN];
|
||||
cursor.read_exact(&mut this)?;
|
||||
this
|
||||
};
|
||||
if &prefix != MESSAGE_ENCODING_PREFIX {
|
||||
return Err(NssaError::TransactionDeserializationError(
|
||||
"Invalid public message prefix".to_string(),
|
||||
));
|
||||
}
|
||||
let bytecode_len = u32_from_cursor(cursor)?;
|
||||
let mut bytecode = vec![0; bytecode_len as usize];
|
||||
let num_bytes = cursor.read(&mut bytecode)?;
|
||||
if num_bytes != bytecode_len as usize {
|
||||
println!("num bytes: {}", num_bytes);
|
||||
return Err(NssaError::TransactionDeserializationError(
|
||||
"Invalid number of bytes".to_string(),
|
||||
));
|
||||
}
|
||||
Ok(Self { bytecode })
|
||||
}
|
||||
}
|
||||
use crate::{ProgramDeploymentTransaction, error::NssaError};
|
||||
|
||||
impl ProgramDeploymentTransaction {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.message.to_bytes()
|
||||
borsh::to_vec(&self).expect("Autoderived borsh serialization failure")
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
Self::from_cursor(&mut cursor)
|
||||
Ok(borsh::from_slice(bytes)?)
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let message = Message::from_cursor(cursor)?;
|
||||
Ok(Self::new(message))
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<u32, NssaError> {
|
||||
let mut word_buf = [0u8; 4];
|
||||
cursor.read_exact(&mut word_buf)?;
|
||||
Ok(u32::from_le_bytes(word_buf))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::{ProgramDeploymentTransaction, program_deployment_transaction::Message};
|
||||
|
||||
#[test]
|
||||
@ -79,8 +19,7 @@ mod tests {
|
||||
let message = Message::new(vec![0xca, 0xfe, 0xca, 0xfe, 0x01, 0x02, 0x03]);
|
||||
let tx = ProgramDeploymentTransaction::new(message);
|
||||
let bytes = tx.to_bytes();
|
||||
let mut cursor = Cursor::new(bytes.as_ref());
|
||||
let tx_from_cursor = ProgramDeploymentTransaction::from_cursor(&mut cursor).unwrap();
|
||||
assert_eq!(tx, tx_from_cursor);
|
||||
let tx_from_bytes = ProgramDeploymentTransaction::from_bytes(&bytes).unwrap();
|
||||
assert_eq!(tx, tx_from_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,155 +1,17 @@
|
||||
// TODO: Consider switching to deriving Borsh
|
||||
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use nssa_core::program::ProgramId;
|
||||
|
||||
use crate::{
|
||||
AccountId, PublicKey, PublicTransaction, Signature,
|
||||
error::NssaError,
|
||||
public_transaction::{Message, WitnessSet},
|
||||
};
|
||||
|
||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||
b"/NSSA/v0.2/TxMessage/Public/\x00\x00\x00\x00";
|
||||
use crate::{PublicTransaction, error::NssaError, public_transaction::Message};
|
||||
|
||||
impl Message {
|
||||
/// Serializes a `Message` into bytes in the following layout:
|
||||
/// PREFIX || <program_id> (4 bytes LE) * 8 || account_ids_len (4 bytes LE) || account_ids (32
|
||||
/// bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes LE * M) || instruction_data_len ||
|
||||
/// instruction_data (4 bytes LE * K) Integers and words are encoded in little-endian byte
|
||||
/// order, and fields appear in the above order.
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||
// program_id: [u32; 8]
|
||||
for word in &self.program_id {
|
||||
bytes.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
// account_ids: Vec<[u8;32]>
|
||||
// serialize length as u32 little endian, then all account_ids concatenated
|
||||
let account_ids_len = self.account_ids.len() as u32;
|
||||
bytes.extend(&account_ids_len.to_le_bytes());
|
||||
for account_id in &self.account_ids {
|
||||
bytes.extend_from_slice(account_id.value());
|
||||
}
|
||||
// nonces: Vec<u128>
|
||||
// serialize length as u32 little endian, then all nonces concatenated in LE
|
||||
let nonces_len = self.nonces.len() as u32;
|
||||
bytes.extend(&nonces_len.to_le_bytes());
|
||||
for nonce in &self.nonces {
|
||||
bytes.extend(&nonce.to_le_bytes());
|
||||
}
|
||||
// instruction_data: Vec<u32>
|
||||
// serialize length as u32 little endian, then all account_ids concatenated
|
||||
let instr_len = self.instruction_data.len() as u32;
|
||||
bytes.extend(&instr_len.to_le_bytes());
|
||||
for word in &self.instruction_data {
|
||||
bytes.extend(&word.to_le_bytes());
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let prefix = {
|
||||
let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN];
|
||||
cursor.read_exact(&mut this)?;
|
||||
this
|
||||
};
|
||||
if &prefix != MESSAGE_ENCODING_PREFIX {
|
||||
return Err(NssaError::TransactionDeserializationError(
|
||||
"Invalid public message prefix".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let program_id: ProgramId = {
|
||||
let mut this = [0u32; 8];
|
||||
for item in &mut this {
|
||||
*item = u32_from_cursor(cursor)?;
|
||||
}
|
||||
this
|
||||
};
|
||||
let account_ids_len = u32_from_cursor(cursor)?;
|
||||
let mut account_ids = Vec::with_capacity(account_ids_len as usize);
|
||||
for _ in 0..account_ids_len {
|
||||
let mut value = [0u8; 32];
|
||||
cursor.read_exact(&mut value)?;
|
||||
account_ids.push(AccountId::new(value))
|
||||
}
|
||||
let nonces_len = u32_from_cursor(cursor)?;
|
||||
let mut nonces = Vec::with_capacity(nonces_len as usize);
|
||||
for _ in 0..nonces_len {
|
||||
let mut buf = [0u8; 16];
|
||||
cursor.read_exact(&mut buf)?;
|
||||
nonces.push(u128::from_le_bytes(buf))
|
||||
}
|
||||
let instruction_data_len = u32_from_cursor(cursor)?;
|
||||
let mut instruction_data = Vec::with_capacity(instruction_data_len as usize);
|
||||
for _ in 0..instruction_data_len {
|
||||
let word = u32_from_cursor(cursor)?;
|
||||
instruction_data.push(word)
|
||||
}
|
||||
Ok(Self {
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WitnessSet {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
let size = self.signatures_and_public_keys().len() as u32;
|
||||
bytes.extend_from_slice(&size.to_le_bytes());
|
||||
for (signature, public_key) in self.signatures_and_public_keys() {
|
||||
bytes.extend_from_slice(signature.to_bytes());
|
||||
bytes.extend_from_slice(public_key.to_bytes());
|
||||
}
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let num_signatures: u32 = {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf)?;
|
||||
u32::from_le_bytes(buf)
|
||||
};
|
||||
let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize);
|
||||
for _i in 0..num_signatures {
|
||||
let signature = Signature::from_cursor(cursor)?;
|
||||
let public_key = PublicKey::from_cursor(cursor)?;
|
||||
signatures_and_public_keys.push((signature, public_key))
|
||||
}
|
||||
Ok(Self {
|
||||
signatures_and_public_keys,
|
||||
})
|
||||
borsh::to_vec(&self).expect("Autoderived borsh serialization failure")
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicTransaction {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = self.message().to_bytes();
|
||||
bytes.extend_from_slice(&self.witness_set().to_bytes());
|
||||
bytes
|
||||
borsh::to_vec(&self).expect("Autoderived borsh serialization failure")
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
Self::from_cursor(&mut cursor)
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let message = Message::from_cursor(cursor)?;
|
||||
let witness_set = WitnessSet::from_cursor(cursor)?;
|
||||
Ok(PublicTransaction::new(message, witness_set))
|
||||
Ok(borsh::from_slice(bytes)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<u32, NssaError> {
|
||||
let mut word_buf = [0u8; 4];
|
||||
cursor.read_exact(&mut word_buf)?;
|
||||
Ok(u32::from_le_bytes(word_buf))
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput,
|
||||
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||
@ -13,7 +14,7 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Proof of the privacy preserving execution circuit
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Proof(pub(crate) Vec<u8>);
|
||||
|
||||
/// Generates a proof of the execution of a NSSA program inside the privacy preserving execution
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, Nonce},
|
||||
@ -9,7 +10,7 @@ use crate::{AccountId, error::NssaError};
|
||||
|
||||
pub type ViewTag = u8;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct EncryptedAccountData {
|
||||
pub ciphertext: Ciphertext,
|
||||
pub epk: EphemeralPublicKey,
|
||||
@ -42,7 +43,7 @@ impl EncryptedAccountData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Message {
|
||||
pub(crate) public_account_ids: Vec<AccountId>,
|
||||
pub(crate) nonces: Vec<Nonce>,
|
||||
@ -90,8 +91,6 @@ impl Message {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use nssa_core::{
|
||||
Commitment, EncryptionScheme, Nullifier, NullifierPublicKey, SharedSecretKey,
|
||||
account::Account,
|
||||
@ -140,17 +139,6 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_serialization_roundtrip() {
|
||||
let message = message_for_tests();
|
||||
|
||||
let bytes = message.to_bytes();
|
||||
let mut cursor = Cursor::new(bytes.as_ref());
|
||||
let message_from_cursor = Message::from_cursor(&mut cursor).unwrap();
|
||||
|
||||
assert_eq!(message, message_from_cursor);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypted_account_data_constructor() {
|
||||
let npk = NullifierPublicKey::from(&[1; 32]);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, AccountWithMetadata},
|
||||
@ -12,7 +13,7 @@ use crate::{
|
||||
privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct PrivacyPreservingTransaction {
|
||||
pub message: Message,
|
||||
witness_set: WitnessSet,
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
use crate::{
|
||||
PrivateKey, PublicKey, Signature,
|
||||
privacy_preserving_transaction::{circuit::Proof, message::Message},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct WitnessSet {
|
||||
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
|
||||
pub(crate) proof: Proof,
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Message {
|
||||
pub(crate) bytecode: Vec<u8>,
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
use crate::{
|
||||
V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ProgramDeploymentTransaction {
|
||||
pub(crate) message: Message,
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
account::Nonce,
|
||||
program::{InstructionData, ProgramId},
|
||||
@ -6,7 +7,7 @@ use serde::Serialize;
|
||||
|
||||
use crate::{AccountId, error::NssaError, program::Program};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Message {
|
||||
pub(crate) program_id: ProgramId,
|
||||
pub(crate) account_ids: Vec<AccountId>,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::{DEFAULT_PROGRAM_ID, validate_execution},
|
||||
@ -12,7 +13,7 @@ use crate::{
|
||||
public_transaction::{Message, WitnessSet},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct PublicTransaction {
|
||||
message: Message,
|
||||
witness_set: WitnessSet,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct WitnessSet {
|
||||
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use crate::{PublicKey, Signature, error::NssaError};
|
||||
|
||||
impl PublicKey {
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let mut value = [0u8; 32];
|
||||
cursor.read_exact(&mut value)?;
|
||||
Self::try_new(value)
|
||||
}
|
||||
|
||||
pub(crate) fn to_bytes(&self) -> &[u8] {
|
||||
self.value()
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||
let mut value = [0u8; 64];
|
||||
cursor.read_exact(&mut value)?;
|
||||
Ok(Self { value })
|
||||
}
|
||||
|
||||
pub(crate) fn to_bytes(&self) -> &[u8] {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
mod encoding;
|
||||
mod private_key;
|
||||
mod public_key;
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
pub use private_key::PrivateKey;
|
||||
pub use public_key::PublicKey;
|
||||
use rand::{RngCore, rngs::OsRng};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Signature {
|
||||
value: [u8; 64],
|
||||
}
|
||||
|
||||
@ -1,11 +1,26 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::account::AccountId;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::{PrivateKey, error::NssaError};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize)]
|
||||
pub struct PublicKey([u8; 32]);
|
||||
|
||||
impl BorshDeserialize for PublicKey {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut buf = [0u8; 32];
|
||||
reader.read_exact(&mut buf)?;
|
||||
|
||||
Self::try_new(buf).map_err(|_| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"Invalid public key: not a valid point",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicKey {
|
||||
pub fn new_from_private_key(key: &PrivateKey) -> Self {
|
||||
let value = {
|
||||
@ -18,7 +33,7 @@ impl PublicKey {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub(super) fn try_new(value: [u8; 32]) -> Result<Self, NssaError> {
|
||||
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaError> {
|
||||
// Check point is valid
|
||||
let _ = secp256k1::XOnlyPublicKey::from_byte_array(value)
|
||||
.map_err(|_| NssaError::InvalidPublicKey)?;
|
||||
@ -92,4 +107,14 @@ mod test {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_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);
|
||||
}
|
||||
}
|
||||
|
||||
1
nssa/test_program_methods/guest/Cargo.lock
generated
1
nssa/test_program_methods/guest/Cargo.lock
generated
@ -1579,6 +1579,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
name = "nssa-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"chacha20",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user