Skip to content

Commit

Permalink
Restricting the maximum size of memo (#263)
Browse files Browse the repository at this point in the history
* check memo size

* parallel

* clean

* fix

* fmt

* tracer memo

* feature

* typo

* Add more check in memo keytype

* Hotfix

* Hotfix

---------

Co-authored-by: Sun <94740291+findora-sun@users.noreply.github.com>
  • Loading branch information
confuseSUN and findora-sun authored Apr 26, 2023
1 parent 5bfef83 commit c68513e
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 6 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,31 @@ jobs:
cd smoke-tests/
cargo nextest run --features=parallel
cargo test --doc
xfr_tracing_check:
name: Check xfr_tracing
runs-on: ubuntu-latest
env:
RUSTFLAGS: -Dwarnings
CARGO_TERM_COLOR: always
strategy:
fail-fast: true
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@nextest
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-xfr_tracing-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: xfr_tracing test
run: |
cd smoke-tests/
cargo nextest run --features=xfr-tracing
cargo test --doc
consistency_check:
name: Check verifier parameters
Expand Down
3 changes: 2 additions & 1 deletion api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,5 @@ parallel = [
]
gen = ["parallel", "structopt"]
lightweight = [] # Minimize size for only AR2ABAR and ABAR2AR.
print-trace = ['noah-algebra/print-trace']
print-trace = ['noah-algebra/print-trace']
xfr-tracing = []
55 changes: 54 additions & 1 deletion api/src/anon_xfr/abar_to_abar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ use crate::anon_xfr::{
OpenAnonAssetRecord, PayeeWitness, PayeeWitnessVars, PayerWitness, PayerWitnessVars,
},
AXfrAddressFoldingInstance, AXfrAddressFoldingWitness, AXfrPlonkPf, TurboPlonkCS, AMOUNT_LEN,
FEE_TYPE, TREE_DEPTH,
FEE_TYPE, MAX_AXFR_MEMO_SIZE, TREE_DEPTH,
};
use crate::errors::NoahError;
use crate::keys::{KeyPair, PublicKey, PublicKeyInner, SecretKey};
use crate::parameters::params::ProverParams;
use crate::parameters::params::{AddressFormat, VerifierParams};
use crate::parameters::{
MAX_ANONYMOUS_RECORD_NUMBER_CONSOLIDATION_RECEIVER, MAX_ANONYMOUS_RECORD_NUMBER_ONE_INPUT,
MAX_ANONYMOUS_RECORD_NUMBER_STANDARD,
};
use digest::{consts::U64, Digest};
use merlin::Transcript;
use noah_algebra::{bls12_381::BLSScalar, prelude::*};
Expand Down Expand Up @@ -272,6 +276,30 @@ pub fn verify_anon_xfr_note<D: Digest<OutputSize = U64> + Default>(
if *merkle_root != note.body.merkle_root {
return Err(eg!(NoahError::AXfrVerificationError));
}

// Check the memo size.
let max_memo_len = if note.body.inputs.len() == 1 {
MAX_ANONYMOUS_RECORD_NUMBER_ONE_INPUT
} else if note.body.inputs.len() > 1
&& note.body.inputs.len() <= MAX_ANONYMOUS_RECORD_NUMBER_STANDARD
{
MAX_ANONYMOUS_RECORD_NUMBER_STANDARD
} else {
MAX_ANONYMOUS_RECORD_NUMBER_CONSOLIDATION_RECEIVER
};

if note.body.owner_memos.len() != note.body.outputs.len()
|| note.body.owner_memos.len() > max_memo_len
{
return Err(eg!(NoahError::AXfrVerificationError));
}

for memo in note.body.owner_memos.iter() {
if memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}
}

let payees_commitments = note
.body
.outputs
Expand Down Expand Up @@ -324,6 +352,31 @@ pub fn batch_verify_anon_xfr_note<D: Digest<OutputSize = U64> + Default + Sync +
return Err(eg!(NoahError::AXfrVerificationError));
}

// Check the memo size.
for note in notes.iter() {
let max_memo_len = if note.body.inputs.len() == 1 {
MAX_ANONYMOUS_RECORD_NUMBER_ONE_INPUT
} else if note.body.inputs.len() > 1
&& note.body.inputs.len() <= MAX_ANONYMOUS_RECORD_NUMBER_STANDARD
{
MAX_ANONYMOUS_RECORD_NUMBER_STANDARD
} else {
MAX_ANONYMOUS_RECORD_NUMBER_CONSOLIDATION_RECEIVER
};

if note.body.owner_memos.len() != note.body.outputs.len()
|| note.body.owner_memos.len() > max_memo_len
{
return Err(eg!(NoahError::AXfrVerificationError));
}

for memo in note.body.owner_memos.iter() {
if memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}
}
}

let is_ok = params
.par_iter()
.zip(notes)
Expand Down
12 changes: 12 additions & 0 deletions api/src/anon_xfr/abar_to_ar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ pub fn verify_abar_to_ar_note<D: Digest<OutputSize = U64> + Default>(
return Err(eg!(NoahError::ParameterError));
}

// Require the output memo is none.
if note.body.memo.is_some() {
return Err(eg!(NoahError::ParameterError));
}

let mut transcript = Transcript::new(ABAR_TO_AR_FOLDING_PROOF_TRANSCRIPT);

let address_folding_public_input = match &note.folding_instance {
Expand Down Expand Up @@ -269,6 +274,13 @@ pub fn batch_verify_abar_to_ar_note<D: Digest<OutputSize = U64> + Default + Sync
return Err(eg!(NoahError::ParameterError));
}

// Require the output memo is none.
for note in notes.iter() {
if note.body.memo.is_some() {
return Err(eg!(NoahError::ParameterError));
}
}

if merkle_roots
.par_iter()
.zip(notes)
Expand Down
9 changes: 9 additions & 0 deletions api/src/anon_xfr/abar_to_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::anon_xfr::{
use crate::keys::{KeyPair, PublicKey, SecretKey};
use crate::parameters::params::ProverParams;
use crate::parameters::params::VerifierParams;
use crate::xfr::structs::check_memo_size;
use crate::xfr::{
asset_record::{build_open_asset_record, AssetRecordType},
structs::{AssetRecordTemplate, BlindAssetRecord, OwnerMemo, XfrAmount, XfrAssetType},
Expand Down Expand Up @@ -281,6 +282,9 @@ pub fn verify_abar_to_bar_note<D: Digest<OutputSize = U64> + Default>(
return Err(eg!(NoahError::AXfrVerificationError));
}

// Check the memo size.
check_memo_size(&note.body.output, &note.body.memo)?;

let bar = note.body.output.clone();
let pc_gens = PedersenCommitmentRistretto::default();

Expand Down Expand Up @@ -409,6 +413,11 @@ pub fn batch_verify_abar_to_bar_note<D: Digest<OutputSize = U64> + Default + Syn
return Err(eg!(NoahError::AXfrVerificationError));
}

// Check the memo size.
for note in notes.iter() {
check_memo_size(&note.body.output, &note.body.memo)?;
}

// Reject anonymous-to-confidential notes whose outputs are transparent.
if notes.par_iter().any(|note| {
note.body.output.get_record_type()
Expand Down
14 changes: 13 additions & 1 deletion api/src/anon_xfr/ar_to_abar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::anon_xfr::{
structs::{
AnonAssetRecord, AxfrOwnerMemo, OpenAnonAssetRecordBuilder, PayeeWitness, PayeeWitnessVars,
},
AXfrPlonkPf, TurboPlonkCS,
AXfrPlonkPf, TurboPlonkCS, MAX_AXFR_MEMO_SIZE,
};
use crate::keys::{KeyPair, PublicKey, PublicKeyInner, Signature};
use crate::parameters::params::ProverParams;
Expand Down Expand Up @@ -65,6 +65,11 @@ pub fn gen_ar_to_abar_note<R: CryptoRng + RngCore>(

/// Verify a transparent-to-anonymous note.
pub fn verify_ar_to_abar_note(params: &VerifierParams, note: &ArToAbarNote) -> Result<()> {
// Check the memo size.
if note.body.memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}

let msg = bincode::serialize(&note.body).c(d!(NoahError::SerializationError))?;
note.body
.input
Expand All @@ -81,6 +86,13 @@ pub fn batch_verify_ar_to_abar_note(
params: &VerifierParams,
notes: &[&ArToAbarNote],
) -> Result<()> {
// Check the memo size.
for note in notes.iter() {
if note.body.memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}
}

let is_ok = notes
.par_iter()
.map(|note| {
Expand Down
14 changes: 13 additions & 1 deletion api/src/anon_xfr/bar_to_abar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::anon_xfr::{
commit, commit_in_cs,
structs::{AnonAssetRecord, AxfrOwnerMemo, OpenAnonAssetRecord, OpenAnonAssetRecordBuilder},
AXfrPlonkPf, TurboPlonkCS, TWO_POW_32,
AXfrPlonkPf, TurboPlonkCS, MAX_AXFR_MEMO_SIZE, TWO_POW_32,
};
use crate::keys::{KeyPair, PublicKey, PublicKeyInner, Signature};
use crate::parameters::params::ProverParams;
Expand Down Expand Up @@ -99,6 +99,11 @@ pub fn verify_bar_to_abar_note(
note: &BarToAbarNote,
bar_pub_key: &PublicKey,
) -> Result<()> {
// Check the memo size.
if note.body.memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}

verify_bar_to_abar(
params,
&note.body.input,
Expand All @@ -118,6 +123,13 @@ pub fn batch_verify_bar_to_abar_note(
notes: &[&BarToAbarNote],
bar_pub_keys: &[&PublicKey],
) -> Result<()> {
// Check the memo size.
for note in notes.iter() {
if note.body.memo.size() > MAX_AXFR_MEMO_SIZE {
return Err(eg!(NoahError::AXfrVerificationError));
}
}

let is_ok = notes
.par_iter()
.zip(bar_pub_keys)
Expand Down
2 changes: 2 additions & 0 deletions api/src/anon_xfr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ const ASSET_TYPE_FRA: AssetType = AssetType([0; ASSET_TYPE_LENGTH]);
pub const FEE_TYPE: AssetType = ASSET_TYPE_FRA;
/// A constant 2^{32}.
pub const TWO_POW_32: u64 = 1 << 32;
/// Restricting the maximum size of memo to 121.
pub const MAX_AXFR_MEMO_SIZE: usize = 121;

pub(crate) type TurboPlonkCS = TurboCS<BLSScalar>;

Expand Down
5 changes: 5 additions & 0 deletions api/src/anon_xfr/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ impl AxfrOwnerMemo {
pub fn decrypt(&self, secret_key: &SecretKey) -> Result<Vec<u8>> {
axfr_hybrid_decrypt(secret_key, &self.0)
}

/// Return the size of the memo.
pub fn size(&self) -> usize {
self.0.len()
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions api/src/xfr/asset_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ fn build_record_input_from_template<R: CryptoRng + RngCore>(
})
}

#[cfg(feature = "xfr-tracing")]
#[cfg(test)]
mod test {
use super::{build_blind_asset_record, build_open_asset_record, open_blind_asset_record};
Expand Down
25 changes: 25 additions & 0 deletions api/src/xfr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub mod proofs;
/// Module for shared structures.
pub mod structs;

#[cfg(feature = "xfr-tracing")]
#[cfg(test)]
pub(crate) mod tests;

Expand Down Expand Up @@ -491,6 +492,30 @@ pub fn batch_verify_xfr_notes<R: CryptoRng + RngCore>(
notes: &[&XfrNote],
policies: &[&XfrNotePoliciesRef<'_>],
) -> Result<()> {
// Check the memo size.
for xfr_note in notes {
if xfr_note.body.outputs.len() != xfr_note.body.owners_memos.len() {
return Err(eg!(NoahError::AXfrVerifierParamsError));
}
#[cfg(not(feature = "xfr-tracing"))]
if xfr_note
.body
.asset_tracing_memos
.iter()
.any(|x| !x.is_empty())
{
return Err(eg!(NoahError::AXfrVerificationError));
}
for (output, memo) in xfr_note
.body
.outputs
.iter()
.zip(xfr_note.body.owners_memos.iter())
{
check_memo_size(output, memo)?
}
}

// Verify each note's multisignature, one by one.
for xfr_note in notes {
verify_transfer_multisig(xfr_note).c(d!())?;
Expand Down
Loading

0 comments on commit c68513e

Please sign in to comment.