Skip to content

Commit 3855252

Browse files
committed
Encrypt payment_metadata when we build the payment secret
In 657ac8f we started committing to the `payment_metadata` in the `payment_secret`. We'd largely assumed that downstream code could simply encrypt the `payment_metadata` itself before passing it to `lightning` and decrypt before reading it from `lightning`. However, this presents a challenge - we'd very much love for that downstream code to avoid adding any extra bytes to its `payment_metadata` if at all possible, but it doesn't have a great way to get a decent IV without simply shoving it in the encrypted `payment_metadata`. Instead, here, we encrypt and decrypt the `payment_metadata` internally in `lightning`. This allows us to reuse the IV that is used for `lightning`-generated `payment_hash`es as the IV for the encrypted `payment_metadata` as well. Sadly, we don't have any similar IV for user-provided `payment_hash`es. In that case, we simply accept the limitations and document that users must avoid encrypting multiple `payment_metadata`s for payments with the same `payment_hash`. This avoids padding the size of the `payment_metadata` and should generally not be a material concern - `payment_hash` reuse should generally not exist anyway, and if it does it should only be in cases where its "the same payment" being retried after failure, at which point `payment_metadata` should hopefully be the same.
1 parent 1743b99 commit 3855252

11 files changed

Lines changed: 403 additions & 125 deletions

fuzz/src/chanmon_consistency.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,7 @@ impl PaymentTracker {
13691369
let mut payment_preimage = PaymentPreimage([0; 32]);
13701370
payment_preimage.0[0..8].copy_from_slice(&self.payment_ctr.to_be_bytes());
13711371
let hash = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
1372-
let secret = dest
1372+
let (secret, _no_metadata) = dest
13731373
.create_inbound_payment_for_hash(hash, None, 3600, None, None)
13741374
.expect("create_inbound_payment_for_hash failed");
13751375
assert!(self.payment_preimages.insert(hash, payment_preimage).is_none());

lightning-liquidity/tests/lsps2_integration_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fn create_jit_invoice(
120120
) -> Result<Bolt11Invoice, ()> {
121121
// LSPS2 requires min_final_cltv_expiry_delta to be at least 2 more than usual.
122122
let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2;
123-
let (payment_hash, payment_secret) = node
123+
let (payment_hash, payment_secret, _) = node
124124
.node
125125
.create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta), None)
126126
.map_err(|e| {

lightning/src/crypto/utils.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ macro_rules! hkdf_extract_expand {
2222
let (k1, k2, _) = hkdf_extract_expand!($salt, $ikm);
2323
(k1, k2)
2424
}};
25-
($salt: expr, $ikm: expr, 7) => {{
25+
($salt: expr, $ikm: expr, 8) => {{
2626
let (k1, k2, prk) = hkdf_extract_expand!($salt, $ikm);
2727

2828
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
@@ -50,18 +50,23 @@ macro_rules! hkdf_extract_expand {
5050
hmac.input(&[7; 1]);
5151
let k7 = Hmac::from_engine(hmac).to_byte_array();
5252

53-
(k1, k2, k3, k4, k5, k6, k7)
53+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
54+
hmac.input(&k7);
55+
hmac.input(&[8; 1]);
56+
let k8 = Hmac::from_engine(hmac).to_byte_array();
57+
58+
(k1, k2, k3, k4, k5, k6, k7, k8)
5459
}};
5560
}
5661

5762
pub fn hkdf_extract_expand_twice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
5863
hkdf_extract_expand!(salt, ikm, 2)
5964
}
6065

61-
pub fn hkdf_extract_expand_7x(
66+
pub fn hkdf_extract_expand_8x(
6267
salt: &[u8], ikm: &[u8],
63-
) -> ([u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32]) {
64-
hkdf_extract_expand!(salt, ikm, 7)
68+
) -> ([u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32]) {
69+
hkdf_extract_expand!(salt, ikm, 8)
6570
}
6671

6772
#[inline]

lightning/src/ln/bolt11_payment_tests.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ fn payment_metadata_end_to_end_for_invoice_with_amount() {
3030

3131
let payment_metadata = vec![42, 43, 44, 45, 46, 47, 48, 49, 42];
3232

33-
let (payment_hash, payment_secret) =
34-
nodes[1].node.create_inbound_payment(None, 7200, None, Some(&payment_metadata)).unwrap();
33+
let (payment_hash, payment_secret, encrypted_metadata) = nodes[1]
34+
.node
35+
.create_inbound_payment(None, 7200, None, Some(payment_metadata.clone()))
36+
.unwrap();
3537

3638
let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
3739
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
@@ -41,7 +43,7 @@ fn payment_metadata_end_to_end_for_invoice_with_amount() {
4143
.duration_since_epoch(timestamp)
4244
.min_final_cltv_expiry_delta(144)
4345
.amount_milli_satoshis(50_000)
44-
.payment_metadata(payment_metadata.clone())
46+
.payment_metadata(encrypted_metadata.unwrap())
4547
.build_raw()
4648
.unwrap();
4749
let sig = nodes[1].keys_manager.backing.sign_invoice(&invoice, Recipient::Node).unwrap();
@@ -97,8 +99,10 @@ fn payment_metadata_end_to_end_for_invoice_with_no_amount() {
9799

98100
let payment_metadata = vec![42, 43, 44, 45, 46, 47, 48, 49, 42];
99101

100-
let (payment_hash, payment_secret) =
101-
nodes[1].node.create_inbound_payment(None, 7200, None, Some(&payment_metadata)).unwrap();
102+
let (payment_hash, payment_secret, encrypted_metadata) = nodes[1]
103+
.node
104+
.create_inbound_payment(None, 7200, None, Some(payment_metadata.clone()))
105+
.unwrap();
102106

103107
let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
104108
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
@@ -107,7 +111,7 @@ fn payment_metadata_end_to_end_for_invoice_with_no_amount() {
107111
.payment_secret(payment_secret)
108112
.duration_since_epoch(timestamp)
109113
.min_final_cltv_expiry_delta(144)
110-
.payment_metadata(payment_metadata.clone())
114+
.payment_metadata(encrypted_metadata.unwrap())
111115
.build_raw()
112116
.unwrap();
113117
let sig = nodes[1].keys_manager.backing.sign_invoice(&invoice, Recipient::Node).unwrap();

lightning/src/ln/channelmanager.rs

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8462,7 +8462,7 @@ impl<
84628462
payment_data,
84638463
payment_context,
84648464
phantom_shared_secret,
8465-
onion_fields,
8465+
mut onion_fields,
84668466
has_recipient_created_payment_secret,
84678467
invoice_request_opt,
84688468
trampoline_shared_secret,
@@ -8603,7 +8603,7 @@ impl<
86038603
let verify_res = inbound_payment::verify(
86048604
payment_hash,
86058605
&payment_data,
8606-
onion_fields.payment_metadata.as_deref(),
8606+
onion_fields.payment_metadata.as_mut(),
86078607
self.highest_seen_timestamp.load(Ordering::Acquire) as u64,
86088608
&self.inbound_payment_key,
86098609
&self.logger,
@@ -14372,24 +14372,24 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1437214372
}
1437314373
}
1437414374

14375-
let (payment_hash, payment_secret) = match payment_hash {
14375+
let (payment_hash, payment_secret, payment_metadata) = match payment_hash {
1437614376
Some(payment_hash) => {
14377-
let payment_secret = self
14377+
let (payment_secret, payment_metadata) = self
1437814378
.create_inbound_payment_for_hash(
1437914379
payment_hash, amount_msats,
1438014380
invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
1438114381
min_final_cltv_expiry_delta,
14382-
payment_metadata.as_deref(),
14382+
payment_metadata,
1438314383
)
1438414384
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
14385-
(payment_hash, payment_secret)
14385+
(payment_hash, payment_secret, payment_metadata)
1438614386
},
1438714387
None => {
1438814388
self
1438914389
.create_inbound_payment(
1439014390
amount_msats, invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
1439114391
min_final_cltv_expiry_delta,
14392-
payment_metadata.as_deref(),
14392+
payment_metadata,
1439314393
)
1439414394
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?
1439514395
},
@@ -14516,8 +14516,7 @@ pub struct Bolt11InvoiceParameters {
1451614516
/// onion by the sender, available as [`RecipientOnionFields::payment_metadata`] via
1451714517
/// [`Event::PaymentClaimable::onion_fields`].
1451814518
///
14519-
/// Note that because it is exposed to the sender in the invoice you should consider encrypting
14520-
/// it. It is committed to, however, so cannot be modified by the sender.
14519+
/// The metadata itself is encrypted and HMAC'd before being stored in the BOLT 11 invoice.
1452114520
pub payment_metadata: Option<Vec<u8>>,
1452214521
}
1452314522

@@ -15023,6 +15022,7 @@ impl<
1502315022
|amount_msats, relative_expiry| {
1502415023
self.create_inbound_payment(Some(amount_msats), relative_expiry, None, None)
1502515024
.map_err(|()| Bolt12SemanticError::InvalidAmount)
15025+
.map(|(preimage, secret, _no_metadata)| (preimage, secret))
1502615026
},
1502715027
None,
1502815028
)?;
@@ -15033,8 +15033,8 @@ impl<
1503315033
Ok(invoice)
1503415034
}
1503515035

15036-
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
15037-
/// to pay us.
15036+
/// Gets a payment secret, payment hash, and encrypts the `payment_metadata` for use in an
15037+
/// invoice given to a third party wishing to pay us.
1503815038
///
1503915039
/// This differs from [`create_inbound_payment_for_hash`] only in that it generates the
1504015040
/// [`PaymentHash`] and [`PaymentPreimage`] for you.
@@ -15065,8 +15065,8 @@ impl<
1506515065
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
1506615066
pub fn create_inbound_payment(
1506715067
&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32,
15068-
min_final_cltv_expiry_delta: Option<u16>, payment_metadata: Option<&[u8]>,
15069-
) -> Result<(PaymentHash, PaymentSecret), ()> {
15068+
min_final_cltv_expiry_delta: Option<u16>, payment_metadata: Option<Vec<u8>>,
15069+
) -> Result<(PaymentHash, PaymentSecret, Option<Vec<u8>>), ()> {
1507015070
inbound_payment::create(
1507115071
&self.inbound_payment_key,
1507215072
min_value_msat,
@@ -15078,8 +15078,8 @@ impl<
1507815078
)
1507915079
}
1508015080

15081-
/// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is
15082-
/// stored external to LDK.
15081+
/// Gets a [`PaymentSecret`] for a given [`PaymentHash`] (for which the payment preimage is
15082+
/// stored external to LDK) and encrypts the `payment_metadata`.
1508315083
///
1508415084
/// A [`PaymentClaimable`] event will only be generated if the [`PaymentSecret`] matches a
1508515085
/// payment secret fetched via this method or [`create_inbound_payment`], and which is at least
@@ -15115,41 +15115,34 @@ impl<
1511515115
/// Note that a malicious eavesdropper can intuit whether an inbound payment was created by
1511615116
/// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime.
1511715117
///
15118-
/// # Note
15119-
///
15120-
/// If you register an inbound payment with this method, then serialize the `ChannelManager`, then
15121-
/// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received.
15122-
///
1512315118
/// Errors if `min_value_msat` is greater than total bitcoin supply.
1512415119
///
15125-
/// If `min_final_cltv_expiry_delta` is set to some value, then the payment will not be receivable
15126-
/// on versions of LDK prior to 0.0.114.
15127-
///
1512815120
/// [`create_inbound_payment`]: Self::create_inbound_payment
1512915121
/// [`PaymentClaimable`]: events::Event::PaymentClaimable
1513015122
pub fn create_inbound_payment_for_hash(
1513115123
&self, payment_hash: PaymentHash, min_value_msat: Option<u64>,
1513215124
invoice_expiry_delta_secs: u32, min_final_cltv_expiry: Option<u16>,
15133-
payment_metadata: Option<&[u8]>,
15134-
) -> Result<PaymentSecret, ()> {
15125+
payment_metadata: Option<Vec<u8>>,
15126+
) -> Result<(PaymentSecret, Option<Vec<u8>>), ()> {
1513515127
inbound_payment::create_from_hash(
1513615128
&self.inbound_payment_key,
1513715129
min_value_msat,
1513815130
payment_hash,
1513915131
invoice_expiry_delta_secs,
15132+
&self.entropy_source,
1514015133
self.highest_seen_timestamp.load(Ordering::Acquire) as u64,
1514115134
min_final_cltv_expiry,
1514215135
payment_metadata,
1514315136
)
1514415137
}
1514515138

15146-
/// Gets an LDK-generated payment preimage from a payment hash, metadata and secret that were
15147-
/// previously returned from [`create_inbound_payment`].
15139+
/// Gets an LDK-generated payment preimage from a payment hash and secret and decrypts the
15140+
/// metadata (if any) that were previously returned from [`create_inbound_payment`].
1514815141
///
1514915142
/// [`create_inbound_payment`]: Self::create_inbound_payment
15150-
pub fn get_payment_preimage(
15143+
pub fn get_payment_preimage_decrypt_metadata(
1515115144
&self, payment_hash: PaymentHash, payment_secret: PaymentSecret,
15152-
payment_metadata: Option<&[u8]>,
15145+
payment_metadata: Option<&mut [u8]>,
1515315146
) -> Result<PaymentPreimage, APIError> {
1515415147
let expanded_key = &self.inbound_payment_key;
1515515148
inbound_payment::get_payment_preimage(
@@ -17235,7 +17228,9 @@ impl<
1723517228
relative_expiry,
1723617229
None,
1723717230
None,
17238-
).map_err(|_| Bolt12SemanticError::InvalidAmount)
17231+
)
17232+
.map_err(|_| Bolt12SemanticError::InvalidAmount)
17233+
.map(|(preimage, secret, _no_metadata)| (preimage, secret))
1723917234
};
1724017235

1724117236
let (result, context) = match invoice_request {
@@ -22137,7 +22132,8 @@ pub mod bench {
2213722132
payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());
2213822133
payment_count += 1;
2213922134
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
22140-
let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None, None).unwrap();
22135+
let (payment_secret, _no_payment_metadata) =
22136+
$node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None, None).unwrap();
2214122137

2214222138
$node_a.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret, 10_000),
2214322139
PaymentId(payment_hash.0),

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2800,7 +2800,7 @@ pub fn get_payment_preimage_hash(
28002800
let payment_preimage = PaymentPreimage([*payment_count; 32]);
28012801
*payment_count += 1;
28022802
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
2803-
let payment_secret = recipient
2803+
let (payment_secret, _) = recipient
28042804
.node
28052805
.create_inbound_payment_for_hash(
28062806
payment_hash,

lightning/src/ln/functional_tests.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ pub fn test_duplicate_htlc_different_direction_onchain() {
293293
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 900_000);
294294

295295
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_value_msats);
296-
let node_a_payment_secret = nodes[0]
296+
let (node_a_payment_secret, _) = nodes[0]
297297
.node
298298
.create_inbound_payment_for_hash(payment_hash, None, 7200, None, None)
299299
.unwrap();
@@ -4159,7 +4159,7 @@ pub fn test_duplicate_payment_hash_one_failure_one_success() {
41594159
let (our_payment_preimage, dup_payment_hash, ..) =
41604160
route_payment(&nodes[0], &[&nodes[1], &nodes[2], &nodes[3]], 900_000);
41614161

4162-
let payment_secret = nodes[4]
4162+
let (payment_secret, _) = nodes[4]
41634163
.node
41644164
.create_inbound_payment_for_hash(dup_payment_hash, None, 7200, None, None)
41654165
.unwrap();
@@ -4428,13 +4428,13 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
44284428

44294429
// 2nd HTLC (not added - smaller than dust limit + HTLC tx fee):
44304430
let path_5: &[&[_]] = &[&[&nodes[2], &nodes[3], &nodes[5]]];
4431-
let payment_secret =
4431+
let (payment_secret, _) =
44324432
nodes[5].node.create_inbound_payment_for_hash(hash_1, None, 7200, None, None).unwrap();
44334433
let route = route_to_5.clone();
44344434
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_1, payment_secret);
44354435

44364436
// 3rd HTLC (not added - smaller than dust limit + HTLC tx fee):
4437-
let payment_secret =
4437+
let (payment_secret, _) =
44384438
nodes[5].node.create_inbound_payment_for_hash(hash_2, None, 7200, None, None).unwrap();
44394439
let route = route_to_5;
44404440
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_2, payment_secret);
@@ -4447,12 +4447,12 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
44474447
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], 1000000);
44484448

44494449
// 6th HTLC:
4450-
let payment_secret =
4450+
let (payment_secret, _) =
44514451
nodes[5].node.create_inbound_payment_for_hash(hash_3, None, 7200, None, None).unwrap();
44524452
send_along_route_with_secret(&nodes[1], route.clone(), path_5, 1000000, hash_3, payment_secret);
44534453

44544454
// 7th HTLC:
4455-
let payment_secret =
4455+
let (payment_secret, _) =
44564456
nodes[5].node.create_inbound_payment_for_hash(hash_4, None, 7200, None, None).unwrap();
44574457
send_along_route_with_secret(&nodes[1], route, path_5, 1000000, hash_4, payment_secret);
44584458

@@ -4461,7 +4461,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
44614461

44624462
// 9th HTLC (not added - smaller than dust limit + HTLC tx fee):
44634463
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], dust_limit_msat);
4464-
let payment_secret =
4464+
let (payment_secret, _) =
44654465
nodes[5].node.create_inbound_payment_for_hash(hash_5, None, 7200, None, None).unwrap();
44664466
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_5, payment_secret);
44674467

@@ -4470,7 +4470,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
44704470

44714471
// 11th HTLC:
44724472
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], 1000000);
4473-
let payment_secret =
4473+
let (payment_secret, _) =
44744474
nodes[5].node.create_inbound_payment_for_hash(hash_6, None, 7200, None, None).unwrap();
44754475
send_along_route_with_secret(&nodes[1], route, path_5, 1000000, hash_6, payment_secret);
44764476

@@ -6064,7 +6064,7 @@ pub fn test_check_htlc_underpaying() {
60646064
.unwrap();
60656065

60666066
let (_, our_payment_hash, _) = get_payment_preimage_hash(&nodes[0], None, None);
6067-
let our_payment_secret = nodes[1]
6067+
let (our_payment_secret, _) = nodes[1]
60686068
.node
60696069
.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None, None)
60706070
.unwrap();
@@ -7233,7 +7233,7 @@ pub fn test_preimage_storage() {
72337233
create_announced_chan_between_nodes(&nodes, 0, 1);
72347234

72357235
{
7236-
let (payment_hash, payment_secret) =
7236+
let (payment_hash, payment_secret, _) =
72377237
nodes[1].node.create_inbound_payment(Some(100_000), 7200, None, None).unwrap();
72387238
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
72397239
let onion = RecipientOnionFields::secret_only(payment_secret, 100_000);
@@ -7278,7 +7278,7 @@ pub fn test_bad_secret_hash() {
72787278

72797279
let random_hash = PaymentHash([42; 32]);
72807280
let random_secret = PaymentSecret([43; 32]);
7281-
let (our_payment_hash, our_payment_secret) =
7281+
let (our_payment_hash, our_payment_secret, _) =
72827282
nodes[1].node.create_inbound_payment(Some(100_000), 2, None, None).unwrap();
72837283
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
72847284

@@ -9496,13 +9496,16 @@ fn do_payment_with_custom_min_final_cltv_expiry(valid_delta: bool, use_user_hash
94969496
get_payment_preimage_hash(&nodes[1], Some(recv_value), Some(min_cltv_expiry_delta));
94979497
(hash, payment_preimage, payment_secret)
94989498
} else {
9499-
let (hash, payment_secret) = nodes[1]
9499+
let (hash, payment_secret, _) = nodes[1]
95009500
.node
95019501
.create_inbound_payment(Some(recv_value), 7200, Some(min_cltv_expiry_delta), None)
95029502
.unwrap();
95039503
(
95049504
hash,
9505-
nodes[1].node.get_payment_preimage(hash, payment_secret, None).unwrap(),
9505+
nodes[1]
9506+
.node
9507+
.get_payment_preimage_decrypt_metadata(hash, payment_secret, None)
9508+
.unwrap(),
95069509
payment_secret,
95079510
)
95089511
};

0 commit comments

Comments
 (0)