mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-17 13:39:39 +00:00
remove shared secrete derivation from r0
This commit is contained in:
parent
20897596b0
commit
d623812c24
@ -11,6 +11,7 @@ program-methods = { path = "program_methods" }
|
|||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
secp256k1 = "0.31.1"
|
secp256k1 = "0.31.1"
|
||||||
|
k256 = "0.13.3"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
borsh = "1.5.7"
|
borsh = "1.5.7"
|
||||||
bytemuck = "1.13"
|
bytemuck = "1.13"
|
||||||
|
|||||||
@ -9,7 +9,6 @@ serde = { version = "1.0", default-features = false }
|
|||||||
thiserror = { version = "2.0.12", optional = true }
|
thiserror = { version = "2.0.12", optional = true }
|
||||||
bytemuck = { version = "1.13", optional = true }
|
bytemuck = { version = "1.13", optional = true }
|
||||||
chacha20 = { version = "0.9", default-features = false }
|
chacha20 = { version = "0.9", default-features = false }
|
||||||
k256 = "0.13.3"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use chacha20::{
|
|||||||
ChaCha20,
|
ChaCha20,
|
||||||
cipher::{KeyIvInit, StreamCipher},
|
cipher::{KeyIvInit, StreamCipher},
|
||||||
};
|
};
|
||||||
|
|
||||||
use risc0_zkvm::{
|
use risc0_zkvm::{
|
||||||
serde::to_vec,
|
serde::to_vec,
|
||||||
sha::{Impl, Sha256},
|
sha::{Impl, Sha256},
|
||||||
@ -25,14 +26,6 @@ use std::io::{Cursor, Read};
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod program;
|
pub mod program;
|
||||||
|
|
||||||
use k256::{
|
|
||||||
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, PublicKey, Scalar,
|
|
||||||
elliptic_curve::{
|
|
||||||
PrimeField,
|
|
||||||
sec1::{FromEncodedPoint, ToEncodedPoint},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "host")]
|
#[cfg(feature = "host")]
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
@ -66,56 +59,23 @@ pub fn compute_root_associated_to_path(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type EphemeralPublicKey = Secp256k1Point;
|
pub type SharedSecretKey = [u8; 32];
|
||||||
pub type IncomingViewingPublicKey = Secp256k1Point;
|
|
||||||
|
|
||||||
pub type EphemeralSecretKey = [u8; 32];
|
|
||||||
|
|
||||||
impl From<&EphemeralSecretKey> for EphemeralPublicKey {
|
|
||||||
fn from(value: &EphemeralSecretKey) -> Self {
|
|
||||||
Secp256k1Point::from_scalar(*value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
|
|
||||||
pub struct Secp256k1Point(pub Vec<u8>);
|
|
||||||
impl Secp256k1Point {
|
|
||||||
pub fn from_scalar(value: [u8; 32]) -> Secp256k1Point {
|
|
||||||
let x_bytes: FieldBytes = value.into();
|
|
||||||
let x = Scalar::from_repr(x_bytes).unwrap();
|
|
||||||
|
|
||||||
let p = ProjectivePoint::GENERATOR * x;
|
|
||||||
let q = AffinePoint::from(p);
|
|
||||||
let enc = q.to_encoded_point(true);
|
|
||||||
|
|
||||||
Self(enc.as_bytes().to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq))]
|
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq))]
|
||||||
pub struct EncryptedAccountData {
|
pub struct Ciphertext(Vec<u8>);
|
||||||
ciphertext: Vec<u8>,
|
|
||||||
epk: EphemeralPublicKey,
|
|
||||||
view_tag: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EncryptedAccountData {
|
impl Ciphertext {
|
||||||
#[cfg(feature = "host")]
|
#[cfg(feature = "host")]
|
||||||
pub fn decrypt(self, isk: &[u8; 32], output_index: u32) -> Option<Account> {
|
pub fn decrypt(self, shared_secret: &[u8; 32], output_index: u32) -> Option<Account> {
|
||||||
let ss_bytes = Self::ecdh(isk, &self.epk.0.clone().try_into().unwrap());
|
|
||||||
let ipk = IncomingViewingPublicKey::from_scalar(*isk);
|
|
||||||
|
|
||||||
let key = Self::kdf(
|
let key = Self::kdf(
|
||||||
ss_bytes,
|
&shared_secret,
|
||||||
&self.epk,
|
// &ipk,
|
||||||
&ipk,
|
|
||||||
// &commitment.to_byte_array(),
|
// &commitment.to_byte_array(),
|
||||||
output_index,
|
output_index,
|
||||||
);
|
);
|
||||||
let mut cipher = ChaCha20::new(&key.into(), &[0; 12].into());
|
let mut cipher = ChaCha20::new(&key.into(), &[0; 12].into());
|
||||||
let mut buffer = self.ciphertext;
|
let mut buffer = self.0;
|
||||||
|
|
||||||
cipher.apply_keystream(&mut buffer);
|
cipher.apply_keystream(&mut buffer);
|
||||||
let mut cursor = Cursor::new(buffer.as_slice());
|
let mut cursor = Cursor::new(buffer.as_slice());
|
||||||
@ -124,71 +84,45 @@ impl EncryptedAccountData {
|
|||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
account: &Account,
|
account: &Account,
|
||||||
// commitment: &Commitment,
|
shared_secret: &[u8; 32],
|
||||||
esk: &EphemeralSecretKey,
|
// npk: &NullifierPublicKey,
|
||||||
npk: &NullifierPublicKey,
|
// ipk: &IncomingViewingPublicKey,
|
||||||
ipk: &IncomingViewingPublicKey,
|
|
||||||
output_index: u32,
|
output_index: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut buffer = account.to_bytes().to_vec();
|
let mut buffer = account.to_bytes().to_vec();
|
||||||
|
|
||||||
let ss_bytes = Self::ecdh(esk, &ipk.0.clone().try_into().unwrap());
|
|
||||||
let epk = EphemeralPublicKey::from(esk);
|
|
||||||
|
|
||||||
let key = Self::kdf(
|
let key = Self::kdf(
|
||||||
ss_bytes,
|
shared_secret,
|
||||||
&epk,
|
// ipk,
|
||||||
ipk,
|
|
||||||
// &commitment.to_byte_array(),
|
// &commitment.to_byte_array(),
|
||||||
output_index,
|
output_index,
|
||||||
);
|
);
|
||||||
let mut cipher = ChaCha20::new(&key.into(), &[0; 12].into());
|
let mut cipher = ChaCha20::new(&key.into(), &[0; 12].into());
|
||||||
cipher.apply_keystream(&mut buffer);
|
cipher.apply_keystream(&mut buffer);
|
||||||
|
|
||||||
let view_tag = Self::view_tag(&npk, &ipk);
|
// let view_tag = Self::view_tag(&npk, &ipk);
|
||||||
Self {
|
Self(buffer)
|
||||||
ciphertext: buffer,
|
|
||||||
epk,
|
|
||||||
view_tag,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kdf(
|
pub fn kdf(
|
||||||
ss_bytes: [u8; 32],
|
ss_bytes: &[u8; 32],
|
||||||
epk: &EphemeralPublicKey,
|
// epk: &EphemeralPublicKey,
|
||||||
ipk: &IncomingViewingPublicKey,
|
// ipk: &IncomingViewingPublicKey,
|
||||||
// commitment: &[u8; 32],
|
// commitment: &[u8; 32],
|
||||||
output_index: u32,
|
output_index: u32,
|
||||||
) -> [u8; 32] {
|
) -> [u8; 32] {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
|
|
||||||
bytes.extend_from_slice(b"NSSA/v0.1/KDF-SHA256");
|
bytes.extend_from_slice(b"NSSA/v0.1/KDF-SHA256");
|
||||||
bytes.extend_from_slice(&ss_bytes);
|
bytes.extend_from_slice(ss_bytes);
|
||||||
bytes.extend_from_slice(&epk.0[..]);
|
// bytes.extend_from_slice(&epk.0[..]);
|
||||||
bytes.extend_from_slice(&ipk.0[..]);
|
// bytes.extend_from_slice(&ipk.0[..]);
|
||||||
// bytes.extend_from_slice(&commitment[..]);
|
// bytes.extend_from_slice(&commitment[..]);
|
||||||
bytes.extend_from_slice(&output_index.to_le_bytes());
|
bytes.extend_from_slice(&output_index.to_le_bytes());
|
||||||
|
|
||||||
Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()
|
Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ecdh(scalar: &[u8; 32], point: &[u8; 33]) -> [u8; 32] {
|
|
||||||
let scalar = Scalar::from_repr((*scalar).into()).unwrap();
|
|
||||||
|
|
||||||
let encoded = EncodedPoint::from_bytes(point).unwrap();
|
|
||||||
let pubkey_affine = AffinePoint::from_encoded_point(&encoded).unwrap();
|
|
||||||
|
|
||||||
let shared = ProjectivePoint::from(pubkey_affine) * scalar;
|
|
||||||
let shared_affine = shared.to_affine();
|
|
||||||
|
|
||||||
let encoded = shared_affine.to_encoded_point(false);
|
|
||||||
let x_bytes_slice = encoded.x().unwrap();
|
|
||||||
let mut x_bytes = [0u8; 32];
|
|
||||||
x_bytes.copy_from_slice(x_bytes_slice);
|
|
||||||
|
|
||||||
x_bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "host")]
|
#[cfg(feature = "host")]
|
||||||
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaCoreError> {
|
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaCoreError> {
|
||||||
let mut u32_bytes = [0; 4];
|
let mut u32_bytes = [0; 4];
|
||||||
@ -198,33 +132,24 @@ impl EncryptedAccountData {
|
|||||||
let mut ciphertext = vec![0; ciphertext_lenght as usize];
|
let mut ciphertext = vec![0; ciphertext_lenght as usize];
|
||||||
cursor.read_exact(&mut ciphertext)?;
|
cursor.read_exact(&mut ciphertext)?;
|
||||||
|
|
||||||
let mut epk_bytes = vec![0; 33];
|
// let mut epk_bytes = vec![0; 33];
|
||||||
cursor.read_exact(&mut epk_bytes)?;
|
// cursor.read_exact(&mut epk_bytes)?;
|
||||||
|
//
|
||||||
|
// let mut tag_bytes = [0; 1];
|
||||||
|
// cursor.read_exact(&mut tag_bytes)?;
|
||||||
|
|
||||||
let mut tag_bytes = [0; 1];
|
Ok(Self(ciphertext))
|
||||||
cursor.read_exact(&mut tag_bytes)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
ciphertext,
|
|
||||||
epk: Secp256k1Point(epk_bytes),
|
|
||||||
view_tag: tag_bytes[0],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view_tag(npk: &NullifierPublicKey, ipk: &&IncomingViewingPublicKey) -> u8 {
|
|
||||||
// TODO: implement
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EncryptedAccountData {
|
impl Ciphertext {
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
let ciphertext_length: u32 = self.ciphertext.len() as u32;
|
let ciphertext_length: u32 = self.0.len() as u32;
|
||||||
bytes.extend_from_slice(&ciphertext_length.to_le_bytes());
|
bytes.extend_from_slice(&ciphertext_length.to_le_bytes());
|
||||||
bytes.extend_from_slice(&self.ciphertext);
|
bytes.extend_from_slice(&self.0);
|
||||||
bytes.extend_from_slice(&self.epk.0);
|
// bytes.extend_from_slice(&self.epk.0);
|
||||||
bytes.push(self.view_tag);
|
// bytes.push(self.view_tag);
|
||||||
|
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
@ -237,8 +162,9 @@ pub struct PrivacyPreservingCircuitInput {
|
|||||||
pub private_account_nonces: Vec<Nonce>,
|
pub private_account_nonces: Vec<Nonce>,
|
||||||
pub private_account_keys: Vec<(
|
pub private_account_keys: Vec<(
|
||||||
NullifierPublicKey,
|
NullifierPublicKey,
|
||||||
IncomingViewingPublicKey,
|
SharedSecretKey,
|
||||||
EphemeralSecretKey,
|
// IncomingViewingPublicKey,
|
||||||
|
// EphemeralSecretKey,
|
||||||
)>,
|
)>,
|
||||||
pub private_account_auth: Vec<(NullifierSecretKey, MembershipProof)>,
|
pub private_account_auth: Vec<(NullifierSecretKey, MembershipProof)>,
|
||||||
pub program_id: ProgramId,
|
pub program_id: ProgramId,
|
||||||
@ -249,7 +175,7 @@ pub struct PrivacyPreservingCircuitInput {
|
|||||||
pub struct PrivacyPreservingCircuitOutput {
|
pub struct PrivacyPreservingCircuitOutput {
|
||||||
pub public_pre_states: Vec<AccountWithMetadata>,
|
pub public_pre_states: Vec<AccountWithMetadata>,
|
||||||
pub public_post_states: Vec<Account>,
|
pub public_post_states: Vec<Account>,
|
||||||
pub encrypted_private_post_states: Vec<EncryptedAccountData>,
|
pub ciphertexts: Vec<Ciphertext>,
|
||||||
pub new_commitments: Vec<Commitment>,
|
pub new_commitments: Vec<Commitment>,
|
||||||
pub new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
pub new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
||||||
}
|
}
|
||||||
@ -268,7 +194,7 @@ mod tests {
|
|||||||
use risc0_zkvm::serde::from_slice;
|
use risc0_zkvm::serde::from_slice;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
EncryptedAccountData, EphemeralPublicKey, PrivacyPreservingCircuitOutput, Secp256k1Point,
|
Ciphertext, PrivacyPreservingCircuitOutput,
|
||||||
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -301,11 +227,10 @@ mod tests {
|
|||||||
data: b"post state data".to_vec(),
|
data: b"post state data".to_vec(),
|
||||||
nonce: 18446744073709551615,
|
nonce: 18446744073709551615,
|
||||||
}],
|
}],
|
||||||
encrypted_private_post_states: vec![EncryptedAccountData {
|
ciphertexts: vec![
|
||||||
ciphertext: vec![255, 255, 1, 1, 2, 2],
|
Ciphertext(vec![255, 255, 1, 1, 2, 2]), // epk: EphemeralPublicKey::from_scalar([123; 32]),
|
||||||
epk: EphemeralPublicKey::from_scalar([123; 32]),
|
// view_tag: 1,
|
||||||
view_tag: 1,
|
],
|
||||||
}],
|
|
||||||
new_commitments: vec![Commitment::new(
|
new_commitments: vec![Commitment::new(
|
||||||
&NullifierPublicKey::from(&[1; 32]),
|
&NullifierPublicKey::from(&[1; 32]),
|
||||||
&Account::default(),
|
&Account::default(),
|
||||||
@ -324,15 +249,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encrypted_account_data_to_bytes_roundtrip() {
|
fn test_ciphertext_to_bytes_roundtrip() {
|
||||||
let data = EncryptedAccountData {
|
let data = Ciphertext(vec![255, 255, 1, 1, 2, 2]);
|
||||||
ciphertext: vec![255, 255, 1, 1, 2, 2],
|
|
||||||
epk: EphemeralPublicKey::from_scalar([123; 32]),
|
|
||||||
view_tag: 95,
|
|
||||||
};
|
|
||||||
let bytes = data.to_bytes();
|
let bytes = data.to_bytes();
|
||||||
let mut cursor = Cursor::new(bytes.as_slice());
|
let mut cursor = Cursor::new(bytes.as_slice());
|
||||||
let data_from_cursor = EncryptedAccountData::from_cursor(&mut cursor).unwrap();
|
let data_from_cursor = Ciphertext::from_cursor(&mut cursor).unwrap();
|
||||||
assert_eq!(data, data_from_cursor);
|
assert_eq!(data, data_from_cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
175
nssa/program_methods/guest/Cargo.lock
generated
175
nssa/program_methods/guest/Cargo.lock
generated
@ -297,24 +297,12 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base16ct"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64ct"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@ -568,18 +556,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-bigint"
|
|
||||||
version = "0.5.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"subtle",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -625,16 +601,6 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "der"
|
|
||||||
version = "0.7.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
|
||||||
dependencies = [
|
|
||||||
"const-oid",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derivative"
|
name = "derivative"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@ -764,20 +730,6 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ecdsa"
|
|
||||||
version = "0.16.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
|
|
||||||
dependencies = [
|
|
||||||
"der",
|
|
||||||
"digest",
|
|
||||||
"elliptic-curve",
|
|
||||||
"rfc6979",
|
|
||||||
"signature",
|
|
||||||
"spki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "educe"
|
name = "educe"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -802,25 +754,6 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "elliptic-curve"
|
|
||||||
version = "0.13.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
|
|
||||||
dependencies = [
|
|
||||||
"base16ct",
|
|
||||||
"crypto-bigint",
|
|
||||||
"digest",
|
|
||||||
"ff",
|
|
||||||
"generic-array",
|
|
||||||
"group",
|
|
||||||
"pkcs8",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"sec1",
|
|
||||||
"subtle",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-io"
|
name = "embedded-io"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -884,16 +817,6 @@ version = "2.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ff"
|
|
||||||
version = "0.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -1006,7 +929,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zeroize",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1042,17 +964,6 @@ version = "0.31.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "group"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
|
||||||
dependencies = [
|
|
||||||
"ff",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
@ -1104,15 +1015,6 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hmac"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
|
||||||
dependencies = [
|
|
||||||
"digest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@ -1403,20 +1305,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "k256"
|
|
||||||
version = "0.13.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"ecdsa",
|
|
||||||
"elliptic-curve",
|
|
||||||
"once_cell",
|
|
||||||
"sha2",
|
|
||||||
"signature",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keccak"
|
name = "keccak"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@ -1588,7 +1476,6 @@ name = "nssa-core"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chacha20",
|
"chacha20",
|
||||||
"k256",
|
|
||||||
"risc0-zkvm",
|
"risc0-zkvm",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -1675,16 +1562,6 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkcs8"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
|
||||||
dependencies = [
|
|
||||||
"der",
|
|
||||||
"spki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "postcard"
|
name = "postcard"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@ -1903,9 +1780,6 @@ name = "rand_core"
|
|||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.2.16",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
@ -1998,16 +1872,6 @@ dependencies = [
|
|||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rfc6979"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
|
||||||
dependencies = [
|
|
||||||
"hmac",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.14"
|
version = "0.17.14"
|
||||||
@ -2329,20 +2193,6 @@ dependencies = [
|
|||||||
"yaml-rust2",
|
"yaml-rust2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sec1"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
|
||||||
dependencies = [
|
|
||||||
"base16ct",
|
|
||||||
"der",
|
|
||||||
"generic-array",
|
|
||||||
"pkcs8",
|
|
||||||
"subtle",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.26"
|
version = "1.0.26"
|
||||||
@ -2422,16 +2272,6 @@ version = "1.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signature"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
|
||||||
dependencies = [
|
|
||||||
"digest",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
@ -2470,16 +2310,6 @@ version = "0.9.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spki"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
|
||||||
dependencies = [
|
|
||||||
"base64ct",
|
|
||||||
"der",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stability"
|
name = "stability"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -3394,8 +3224,3 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[patch.unused]]
|
|
||||||
name = "k256"
|
|
||||||
version = "0.13.3"
|
|
||||||
source = "git+https://github.com/risc0/RustCrypto-elliptic-curves?tag=k256%2Fv0.13.3-risczero.1#ff5d67b095cfcc2569b7789f2079ed87ef2c7756"
|
|
||||||
|
|||||||
@ -8,7 +8,3 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] }
|
risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] }
|
||||||
nssa-core = { path = "../../core" }
|
nssa-core = { path = "../../core" }
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.3-risczero.1" }
|
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,7 @@ use nssa_core::{
|
|||||||
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
||||||
compute_root_associated_to_path,
|
compute_root_associated_to_path,
|
||||||
program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID},
|
program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID},
|
||||||
CommitmentSetDigest, EncryptedAccountData, EphemeralPublicKey, EphemeralSecretKey,
|
Ciphertext, CommitmentSetDigest, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
||||||
IncomingViewingPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -42,7 +41,7 @@ fn main() {
|
|||||||
// and will be populated next.
|
// and will be populated next.
|
||||||
let mut public_pre_states: Vec<AccountWithMetadata> = Vec::new();
|
let mut public_pre_states: Vec<AccountWithMetadata> = Vec::new();
|
||||||
let mut public_post_states: Vec<Account> = Vec::new();
|
let mut public_post_states: Vec<Account> = Vec::new();
|
||||||
let mut encrypted_private_post_states: Vec<EncryptedAccountData> = Vec::new();
|
let mut ciphertexts: Vec<Ciphertext> = Vec::new();
|
||||||
let mut new_commitments: Vec<Commitment> = Vec::new();
|
let mut new_commitments: Vec<Commitment> = Vec::new();
|
||||||
let mut new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)> = Vec::new();
|
let mut new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)> = Vec::new();
|
||||||
|
|
||||||
@ -67,7 +66,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
1 | 2 => {
|
1 | 2 => {
|
||||||
let new_nonce = private_nonces_iter.next().expect("Missing private nonce");
|
let new_nonce = private_nonces_iter.next().expect("Missing private nonce");
|
||||||
let (Npk, Ipk, esk) = private_keys_iter.next().expect("Missing private keys");
|
// let (Npk, Ipk, esk) = private_keys_iter.next().expect("Missing keys");
|
||||||
|
let (Npk, shared_secret) = private_keys_iter.next().expect("Missing keys");
|
||||||
|
|
||||||
if visibility_mask[i] == 1 {
|
if visibility_mask[i] == 1 {
|
||||||
// Private account with authentication
|
// Private account with authentication
|
||||||
@ -116,17 +116,18 @@ fn main() {
|
|||||||
let commitment_post = Commitment::new(Npk, &post_with_updated_values);
|
let commitment_post = Commitment::new(Npk, &post_with_updated_values);
|
||||||
|
|
||||||
// Encrypt and push post state
|
// Encrypt and push post state
|
||||||
let encrypted_account = EncryptedAccountData::new(
|
let encrypted_account = Ciphertext::new(
|
||||||
&post_with_updated_values,
|
&post_with_updated_values,
|
||||||
|
shared_secret,
|
||||||
// &commitment_post,
|
// &commitment_post,
|
||||||
esk,
|
// esk,
|
||||||
Npk,
|
// Npk,
|
||||||
Ipk,
|
// Ipk,
|
||||||
output_index,
|
output_index,
|
||||||
);
|
);
|
||||||
|
|
||||||
new_commitments.push(commitment_post);
|
new_commitments.push(commitment_post);
|
||||||
encrypted_private_post_states.push(encrypted_account);
|
ciphertexts.push(encrypted_account);
|
||||||
output_index += 1;
|
output_index += 1;
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid visibility mask value"),
|
_ => panic!("Invalid visibility mask value"),
|
||||||
@ -148,7 +149,7 @@ fn main() {
|
|||||||
let output = PrivacyPreservingCircuitOutput {
|
let output = PrivacyPreservingCircuitOutput {
|
||||||
public_pre_states,
|
public_pre_states,
|
||||||
public_post_states,
|
public_post_states,
|
||||||
encrypted_private_post_states,
|
ciphertexts,
|
||||||
new_commitments,
|
new_commitments,
|
||||||
new_nullifiers,
|
new_nullifiers,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
CommitmentSetDigest, EphemeralSecretKey, IncomingViewingPublicKey, MembershipProof,
|
CommitmentSetDigest, MembershipProof, PrivacyPreservingCircuitInput,
|
||||||
PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||||
account::{Account, AccountWithMetadata, Nonce, NullifierPublicKey, NullifierSecretKey},
|
account::{Account, AccountWithMetadata, Nonce, NullifierPublicKey, NullifierSecretKey},
|
||||||
program::{InstructionData, ProgramId, ProgramOutput},
|
program::{InstructionData, ProgramId, ProgramOutput},
|
||||||
};
|
};
|
||||||
@ -28,8 +28,9 @@ pub fn execute_and_prove(
|
|||||||
private_account_nonces: &[u128],
|
private_account_nonces: &[u128],
|
||||||
private_account_keys: &[(
|
private_account_keys: &[(
|
||||||
NullifierPublicKey,
|
NullifierPublicKey,
|
||||||
IncomingViewingPublicKey,
|
SharedSecretKey,
|
||||||
EphemeralSecretKey,
|
// IncomingViewingPublicKey,
|
||||||
|
// EphemeralSecretKey,
|
||||||
)],
|
)],
|
||||||
private_account_auth: &[(NullifierSecretKey, MembershipProof)],
|
private_account_auth: &[(NullifierSecretKey, MembershipProof)],
|
||||||
program: &Program,
|
program: &Program,
|
||||||
@ -90,7 +91,7 @@ fn execute_and_prove_program(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
EncryptedAccountData,
|
Ciphertext,
|
||||||
account::{
|
account::{
|
||||||
Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey,
|
Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey,
|
||||||
NullifierSecretKey,
|
NullifierSecretKey,
|
||||||
@ -101,7 +102,10 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
Address, V01State,
|
Address, V01State,
|
||||||
merkle_tree::MerkleTree,
|
merkle_tree::MerkleTree,
|
||||||
privacy_preserving_transaction::circuit::{Proof, execute_and_prove},
|
privacy_preserving_transaction::{
|
||||||
|
circuit::{Proof, execute_and_prove},
|
||||||
|
message::{EncryptedAccountData, EphemeralPublicKey},
|
||||||
|
},
|
||||||
program::Program,
|
program::Program,
|
||||||
state::{
|
state::{
|
||||||
CommitmentSet,
|
CommitmentSet,
|
||||||
@ -147,12 +151,18 @@ mod tests {
|
|||||||
|
|
||||||
let expected_sender_pre = sender.clone();
|
let expected_sender_pre = sender.clone();
|
||||||
let recipient_keys = test_private_account_keys_1();
|
let recipient_keys = test_private_account_keys_1();
|
||||||
|
|
||||||
|
let esk = [3; 32];
|
||||||
|
let shared_secret =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk, &recipient_keys.ivk());
|
||||||
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
let (output, proof) = execute_and_prove(
|
let (output, proof) = execute_and_prove(
|
||||||
&[sender, recipient],
|
&[sender, recipient],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[0, 2],
|
&[0, 2],
|
||||||
&[0xdeadbeef],
|
&[0xdeadbeef],
|
||||||
&[(recipient_keys.npk(), recipient_keys.ivk(), [3; 32])],
|
&[(recipient_keys.npk(), shared_secret)],
|
||||||
&[],
|
&[],
|
||||||
&Program::authenticated_transfer_program(),
|
&Program::authenticated_transfer_program(),
|
||||||
)
|
)
|
||||||
@ -166,11 +176,11 @@ mod tests {
|
|||||||
assert_eq!(sender_post, expected_sender_post);
|
assert_eq!(sender_post, expected_sender_post);
|
||||||
assert_eq!(output.new_commitments.len(), 1);
|
assert_eq!(output.new_commitments.len(), 1);
|
||||||
assert_eq!(output.new_nullifiers.len(), 0);
|
assert_eq!(output.new_nullifiers.len(), 0);
|
||||||
assert_eq!(output.encrypted_private_post_states.len(), 1);
|
assert_eq!(output.ciphertexts.len(), 1);
|
||||||
|
|
||||||
let recipient_post = output.encrypted_private_post_states[0]
|
let recipient_post = output.ciphertexts[0]
|
||||||
.clone()
|
.clone()
|
||||||
.decrypt(&recipient_keys.isk, 0)
|
.decrypt(&shared_secret, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(recipient_post, expected_recipient_post);
|
assert_eq!(recipient_post, expected_recipient_post);
|
||||||
}
|
}
|
||||||
@ -222,14 +232,24 @@ mod tests {
|
|||||||
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let esk_1 = [3; 32];
|
||||||
|
let shared_secret_1 =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk_1, &sender_keys.ivk());
|
||||||
|
let epk_1 = EphemeralPublicKey::from_scalar(esk_1);
|
||||||
|
|
||||||
|
let esk_2 = [5; 32];
|
||||||
|
let shared_secret_2 =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk_2, &recipient_keys.ivk());
|
||||||
|
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
|
||||||
|
|
||||||
let (output, proof) = execute_and_prove(
|
let (output, proof) = execute_and_prove(
|
||||||
&[sender_pre.clone(), recipient],
|
&[sender_pre.clone(), recipient],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[1, 2],
|
&[1, 2],
|
||||||
&[0xdeadbeef1, 0xdeadbeef2],
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
&[
|
&[
|
||||||
(sender_keys.npk(), sender_keys.ivk(), [3; 32]),
|
(sender_keys.npk(), shared_secret_1),
|
||||||
(recipient_keys.npk(), recipient_keys.ivk(), [5; 32]),
|
(recipient_keys.npk(), shared_secret_2),
|
||||||
],
|
],
|
||||||
&[(
|
&[(
|
||||||
sender_keys.nsk,
|
sender_keys.nsk,
|
||||||
@ -244,17 +264,17 @@ mod tests {
|
|||||||
assert!(output.public_post_states.is_empty());
|
assert!(output.public_post_states.is_empty());
|
||||||
assert_eq!(output.new_commitments, expected_new_commitments);
|
assert_eq!(output.new_commitments, expected_new_commitments);
|
||||||
assert_eq!(output.new_nullifiers, expected_new_nullifiers);
|
assert_eq!(output.new_nullifiers, expected_new_nullifiers);
|
||||||
assert_eq!(output.encrypted_private_post_states.len(), 2);
|
assert_eq!(output.ciphertexts.len(), 2);
|
||||||
|
|
||||||
let recipient_post_1 = output.encrypted_private_post_states[0]
|
let recipient_post_1 = output.ciphertexts[0]
|
||||||
.clone()
|
.clone()
|
||||||
.decrypt(&sender_keys.isk, 0)
|
.decrypt(&shared_secret_1, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(recipient_post_1, expected_private_account_1);
|
assert_eq!(recipient_post_1, expected_private_account_1);
|
||||||
|
|
||||||
let recipient_post_2 = output.encrypted_private_post_states[1]
|
let recipient_post_2 = output.ciphertexts[1]
|
||||||
.clone()
|
.clone()
|
||||||
.decrypt(&recipient_keys.isk, 1)
|
.decrypt(&shared_secret_2, 1)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(recipient_post_2, expected_private_account_2);
|
assert_eq!(recipient_post_2, expected_private_account_2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,17 +3,50 @@
|
|||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
EncryptedAccountData,
|
Ciphertext,
|
||||||
account::{Account, Commitment, Nullifier},
|
account::{Account, Commitment, Nullifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Address, error::NssaError};
|
use crate::{
|
||||||
|
Address,
|
||||||
|
error::NssaError,
|
||||||
|
privacy_preserving_transaction::message::{
|
||||||
|
EncryptedAccountData, EphemeralPublicKey, Secp256k1Point,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::message::Message;
|
use super::message::Message;
|
||||||
|
|
||||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
||||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";
|
||||||
|
|
||||||
|
impl EncryptedAccountData {
|
||||||
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = self.ciphertext.to_bytes();
|
||||||
|
bytes.extend_from_slice(&self.epk.0);
|
||||||
|
bytes.push(self.view_tag);
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let ciphertext = Ciphertext::from_cursor(cursor)?;
|
||||||
|
|
||||||
|
let mut epk_bytes = vec![0; 33];
|
||||||
|
cursor.read_exact(&mut epk_bytes)?;
|
||||||
|
let epk = Secp256k1Point(epk_bytes);
|
||||||
|
|
||||||
|
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 {
|
impl Message {
|
||||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||||
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||||
|
|||||||
@ -1,9 +1,80 @@
|
|||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use k256::{
|
||||||
|
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, PublicKey, Scalar,
|
||||||
|
elliptic_curve::{
|
||||||
|
PrimeField,
|
||||||
|
sec1::{FromEncodedPoint, ToEncodedPoint},
|
||||||
|
},
|
||||||
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
CommitmentSetDigest, EncryptedAccountData,
|
Ciphertext, CommitmentSetDigest, PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||||
account::{Account, Commitment, Nonce, Nullifier},
|
account::{Account, Commitment, Nonce, Nullifier},
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::Address;
|
use crate::{Address, error::NssaError};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Secp256k1Point(pub(crate) Vec<u8>);
|
||||||
|
impl Secp256k1Point {
|
||||||
|
pub fn from_scalar(value: [u8; 32]) -> Secp256k1Point {
|
||||||
|
let x_bytes: FieldBytes = value.into();
|
||||||
|
let x = Scalar::from_repr(x_bytes).unwrap();
|
||||||
|
|
||||||
|
let p = ProjectivePoint::GENERATOR * x;
|
||||||
|
let q = AffinePoint::from(p);
|
||||||
|
let enc = q.to_encoded_point(true);
|
||||||
|
|
||||||
|
Self(enc.as_bytes().to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type EphemeralSecretKey = [u8; 32];
|
||||||
|
pub type EphemeralPublicKey = Secp256k1Point;
|
||||||
|
pub type IncomingViewingPublicKey = Secp256k1Point;
|
||||||
|
impl From<&EphemeralSecretKey> for EphemeralPublicKey {
|
||||||
|
fn from(value: &EphemeralSecretKey) -> Self {
|
||||||
|
Secp256k1Point::from_scalar(*value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EncryptedAccountData {
|
||||||
|
pub(crate) ciphertext: Ciphertext,
|
||||||
|
pub(crate) epk: EphemeralPublicKey,
|
||||||
|
pub(crate) view_tag: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncryptedAccountData {
|
||||||
|
pub fn decrypt(
|
||||||
|
self,
|
||||||
|
isk: &[u8; 32],
|
||||||
|
epk: &EphemeralPublicKey,
|
||||||
|
output_index: u32,
|
||||||
|
) -> Option<Account> {
|
||||||
|
let shared_secret = Self::compute_shared_secret(isk, &epk);
|
||||||
|
self.ciphertext.decrypt(&shared_secret, output_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_shared_secret(scalar: &[u8; 32], point: &Secp256k1Point) -> SharedSecretKey {
|
||||||
|
let scalar = Scalar::from_repr((*scalar).into()).unwrap();
|
||||||
|
let point: [u8; 33] = point.0.clone().try_into().unwrap();
|
||||||
|
|
||||||
|
let encoded = EncodedPoint::from_bytes(point).unwrap();
|
||||||
|
let pubkey_affine = AffinePoint::from_encoded_point(&encoded).unwrap();
|
||||||
|
|
||||||
|
let shared = ProjectivePoint::from(pubkey_affine) * scalar;
|
||||||
|
let shared_affine = shared.to_affine();
|
||||||
|
|
||||||
|
let encoded = shared_affine.to_encoded_point(false);
|
||||||
|
let x_bytes_slice = encoded.x().unwrap();
|
||||||
|
let mut x_bytes = [0u8; 32];
|
||||||
|
x_bytes.copy_from_slice(x_bytes_slice);
|
||||||
|
|
||||||
|
x_bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
@ -16,22 +87,36 @@ pub struct Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub fn new(
|
pub fn try_from_circuit_output(
|
||||||
public_addresses: Vec<Address>,
|
public_addresses: Vec<Address>,
|
||||||
nonces: Vec<Nonce>,
|
nonces: Vec<Nonce>,
|
||||||
public_post_states: Vec<Account>,
|
ephemeral_public_keys: Vec<EphemeralPublicKey>,
|
||||||
encrypted_private_post_states: Vec<EncryptedAccountData>,
|
output: PrivacyPreservingCircuitOutput,
|
||||||
new_commitments: Vec<Commitment>,
|
) -> Result<Self, NssaError> {
|
||||||
new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
if ephemeral_public_keys.len() != output.ciphertexts.len() {
|
||||||
) -> Self {
|
return Err(NssaError::InvalidInput(
|
||||||
Self {
|
"Ephemeral public keys and ciphertexts length mismatch".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let encrypted_private_post_states = output
|
||||||
|
.ciphertexts
|
||||||
|
.into_iter()
|
||||||
|
.zip(ephemeral_public_keys)
|
||||||
|
.map(|(ciphertext, epk)| EncryptedAccountData {
|
||||||
|
ciphertext,
|
||||||
|
epk,
|
||||||
|
view_tag: 0, // TODO: implement
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(Self {
|
||||||
public_addresses,
|
public_addresses,
|
||||||
nonces,
|
nonces,
|
||||||
public_post_states,
|
public_post_states: output.public_post_states,
|
||||||
encrypted_private_post_states,
|
encrypted_private_post_states,
|
||||||
new_commitments,
|
new_commitments: output.new_commitments,
|
||||||
new_nullifiers,
|
new_nullifiers: output.new_nullifiers,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,23 +163,6 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_constructor() {
|
|
||||||
let message = message_for_tests();
|
|
||||||
let expected_message = message.clone();
|
|
||||||
|
|
||||||
let message = Message::new(
|
|
||||||
message.public_addresses,
|
|
||||||
message.nonces,
|
|
||||||
message.public_post_states,
|
|
||||||
message.encrypted_private_post_states,
|
|
||||||
message.new_commitments,
|
|
||||||
message.new_nullifiers,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(message, expected_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_message_serialization_roundtrip() {
|
fn test_message_serialization_roundtrip() {
|
||||||
let message = message_for_tests();
|
let message = message_for_tests();
|
||||||
|
|||||||
@ -5,6 +5,6 @@ mod witness_set;
|
|||||||
|
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
|
|
||||||
pub use message::Message;
|
pub use message::{Message, IncomingViewingPublicKey, EphemeralPublicKey, EphemeralSecretKey, EncryptedAccountData};
|
||||||
pub use transaction::PrivacyPreservingTransaction;
|
pub use transaction::PrivacyPreservingTransaction;
|
||||||
pub use witness_set::WitnessSet;
|
pub use witness_set::WitnessSet;
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use nssa_core::account::{Account, AccountWithMetadata, Commitment, Nullifier};
|
use nssa_core::account::{Account, AccountWithMetadata, Commitment, Nullifier};
|
||||||
use nssa_core::{CommitmentSetDigest, EncryptedAccountData, PrivacyPreservingCircuitOutput};
|
use nssa_core::{Ciphertext, CommitmentSetDigest, PrivacyPreservingCircuitOutput};
|
||||||
|
|
||||||
use crate::error::NssaError;
|
use crate::error::NssaError;
|
||||||
use crate::privacy_preserving_transaction::circuit::Proof;
|
use crate::privacy_preserving_transaction::circuit::Proof;
|
||||||
|
use crate::privacy_preserving_transaction::message::EncryptedAccountData;
|
||||||
use crate::{Address, V01State};
|
use crate::{Address, V01State};
|
||||||
|
|
||||||
use super::message::Message;
|
use super::message::Message;
|
||||||
@ -145,7 +146,11 @@ fn check_privacy_preserving_circuit_proof_is_valid(
|
|||||||
let output = PrivacyPreservingCircuitOutput {
|
let output = PrivacyPreservingCircuitOutput {
|
||||||
public_pre_states: public_pre_states.to_vec(),
|
public_pre_states: public_pre_states.to_vec(),
|
||||||
public_post_states: public_post_states.to_vec(),
|
public_post_states: public_post_states.to_vec(),
|
||||||
encrypted_private_post_states: encrypted_private_post_states.to_vec(),
|
ciphertexts: encrypted_private_post_states
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|value| value.ciphertext)
|
||||||
|
.collect(),
|
||||||
new_commitments: new_commitments.to_vec(),
|
new_commitments: new_commitments.to_vec(),
|
||||||
new_nullifiers: new_nullifiers.to_vec(),
|
new_nullifiers: new_nullifiers.to_vec(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -222,14 +222,15 @@ pub mod tests {
|
|||||||
Address, PublicKey, PublicTransaction, V01State,
|
Address, PublicKey, PublicTransaction, V01State,
|
||||||
error::NssaError,
|
error::NssaError,
|
||||||
privacy_preserving_transaction::{
|
privacy_preserving_transaction::{
|
||||||
Message, PrivacyPreservingTransaction, WitnessSet, circuit,
|
EncryptedAccountData, EphemeralPublicKey, IncomingViewingPublicKey, Message,
|
||||||
|
PrivacyPreservingTransaction, WitnessSet, circuit,
|
||||||
},
|
},
|
||||||
program::Program,
|
program::Program,
|
||||||
public_transaction,
|
public_transaction,
|
||||||
signature::PrivateKey,
|
signature::PrivateKey,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
IncomingViewingPublicKey,
|
Ciphertext,
|
||||||
account::{
|
account::{
|
||||||
Account, AccountWithMetadata, Commitment, Nonce, Nullifier, NullifierPublicKey,
|
Account, AccountWithMetadata, Commitment, Nonce, Nullifier, NullifierPublicKey,
|
||||||
NullifierSecretKey,
|
NullifierSecretKey,
|
||||||
@ -780,11 +781,11 @@ pub mod tests {
|
|||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
state: &V01State,
|
state: &V01State,
|
||||||
) -> PrivacyPreservingTransaction {
|
) -> PrivacyPreservingTransaction {
|
||||||
let esk = [3; 32];
|
|
||||||
let sender = AccountWithMetadata {
|
let sender = AccountWithMetadata {
|
||||||
account: state.get_account_by_address(&sender_keys.address()),
|
account: state.get_account_by_address(&sender_keys.address()),
|
||||||
is_authorized: true,
|
is_authorized: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let sender_nonce = sender.account.nonce;
|
let sender_nonce = sender.account.nonce;
|
||||||
|
|
||||||
let recipient = AccountWithMetadata {
|
let recipient = AccountWithMetadata {
|
||||||
@ -792,25 +793,28 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
is_authorized: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let esk = [3; 32];
|
||||||
|
let shared_secret =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk, &recipient_keys.ivk());
|
||||||
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
let (output, proof) = circuit::execute_and_prove(
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
&[sender, recipient],
|
&[sender, recipient],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[0, 2],
|
&[0, 2],
|
||||||
&[0xdeadbeef],
|
&[0xdeadbeef],
|
||||||
&[(recipient_keys.npk(), recipient_keys.ivk(), esk)],
|
&[(recipient_keys.npk(), shared_secret)],
|
||||||
&[],
|
&[],
|
||||||
&Program::authenticated_transfer_program(),
|
&Program::authenticated_transfer_program(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::try_from_circuit_output(
|
||||||
vec![sender_keys.address()],
|
vec![sender_keys.address()],
|
||||||
vec![sender_nonce],
|
vec![sender_nonce],
|
||||||
output.public_post_states,
|
vec![epk],
|
||||||
output.encrypted_private_post_states,
|
output,
|
||||||
output.new_commitments.clone(),
|
).unwrap();
|
||||||
output.new_nullifiers,
|
|
||||||
);
|
|
||||||
|
|
||||||
let witness_set = WitnessSet::for_message(&message, proof, &[&sender_keys.signing_key]);
|
let witness_set = WitnessSet::for_message(&message, proof, &[&sender_keys.signing_key]);
|
||||||
PrivacyPreservingTransaction::new(message, witness_set)
|
PrivacyPreservingTransaction::new(message, witness_set)
|
||||||
@ -835,14 +839,24 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
is_authorized: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let esk_1 = [3; 32];
|
||||||
|
let shared_secret_1 =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk_1, &sender_keys.ivk());
|
||||||
|
let epk_1 = EphemeralPublicKey::from_scalar(esk_1);
|
||||||
|
|
||||||
|
let esk_2 = [3; 32];
|
||||||
|
let shared_secret_2 =
|
||||||
|
EncryptedAccountData::compute_shared_secret(&esk_2, &recipient_keys.ivk());
|
||||||
|
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
|
||||||
|
|
||||||
let (output, proof) = circuit::execute_and_prove(
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
&[sender_pre, recipient_pre],
|
&[sender_pre, recipient_pre],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[1, 2],
|
&[1, 2],
|
||||||
&new_nonces,
|
&new_nonces,
|
||||||
&[
|
&[
|
||||||
(sender_keys.npk(), sender_keys.ivk(), [3; 32]),
|
(sender_keys.npk(), shared_secret_1),
|
||||||
(recipient_keys.npk(), recipient_keys.ivk(), [4; 32]),
|
(recipient_keys.npk(), shared_secret_2),
|
||||||
],
|
],
|
||||||
&[(
|
&[(
|
||||||
sender_keys.nsk,
|
sender_keys.nsk,
|
||||||
@ -856,14 +870,7 @@ pub mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::try_from_circuit_output(vec![], vec![], vec![epk_1, epk_2], output).unwrap();
|
||||||
vec![],
|
|
||||||
vec![],
|
|
||||||
output.public_post_states,
|
|
||||||
output.encrypted_private_post_states,
|
|
||||||
output.new_commitments.clone(),
|
|
||||||
output.new_nullifiers,
|
|
||||||
);
|
|
||||||
|
|
||||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
|
|
||||||
@ -889,12 +896,16 @@ pub mod tests {
|
|||||||
is_authorized: false,
|
is_authorized: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let esk = [3; 32];
|
||||||
|
let shared_secret = EncryptedAccountData::compute_shared_secret(&esk, &sender_keys.ivk());
|
||||||
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
let (output, proof) = circuit::execute_and_prove(
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
&[sender_pre, recipient_pre],
|
&[sender_pre, recipient_pre],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[1, 0],
|
&[1, 0],
|
||||||
&[new_nonce],
|
&[new_nonce],
|
||||||
&[(sender_keys.npk(), sender_keys.ivk(), [3; 32])],
|
&[(sender_keys.npk(), shared_secret)],
|
||||||
&[(
|
&[(
|
||||||
sender_keys.nsk,
|
sender_keys.nsk,
|
||||||
state
|
state
|
||||||
@ -907,14 +918,12 @@ pub mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::try_from_circuit_output(
|
||||||
vec![recipient_address.clone()],
|
vec![recipient_address.clone()],
|
||||||
vec![],
|
vec![],
|
||||||
output.public_post_states,
|
vec![epk],
|
||||||
output.encrypted_private_post_states,
|
output,
|
||||||
output.new_commitments.clone(),
|
).unwrap();
|
||||||
output.new_nullifiers,
|
|
||||||
);
|
|
||||||
|
|
||||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user