@@ -13,7 +13,7 @@ use crate::ln::msgs;
13
13
use crate :: ln:: wire:: Encode ;
14
14
use crate :: routing:: gossip:: NetworkUpdate ;
15
15
use crate :: routing:: router:: { BlindedTail , Path , RouteHop } ;
16
- use crate :: sign:: NodeSigner ;
16
+ use crate :: sign:: { NodeSigner , Recipient } ;
17
17
use crate :: util:: chacha20:: { ChaCha20 , ChaChaReader } ;
18
18
use crate :: util:: errors:: { self , APIError } ;
19
19
use crate :: util:: ser:: { Readable , ReadableArgs , Writeable , Writer , LengthCalculatingWriter } ;
@@ -935,6 +935,160 @@ pub(crate) fn decode_next_payment_hop<NS: Deref>(
935
935
}
936
936
}
937
937
938
+ /// Build a payment onion, returning the first hop msat and cltv values as well.
939
+ pub fn create_payment_onion < T > (
940
+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
941
+ recipient_onion : RecipientOnionFields , starting_htlc_offset : u32 , payment_hash : PaymentHash ,
942
+ keysend_preimage : Option < PaymentPreimage > , prng_seed : [ u8 ; 32 ] ) -> Result < ( u64 , u32 , msgs:: OnionPacket ) , ( ) >
943
+ where
944
+ T : secp256k1:: Signing
945
+ {
946
+ let onion_keys = construct_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| ( ) ) ?;
947
+ let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
948
+ & path,
949
+ total_msat,
950
+ recipient_onion,
951
+ starting_htlc_offset,
952
+ & keysend_preimage,
953
+ ) . map_err ( |_| ( ) ) ?;
954
+ let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, & payment_hash) ?;
955
+ Ok ( ( htlc_msat, htlc_cltv, onion_packet) )
956
+ }
957
+
958
+ /// Forwarded Payment, including next hop details
959
+ #[ derive( Debug ) ]
960
+ pub struct ForwardedPayment {
961
+ /// short channel id of the next hop
962
+ pub short_channel_id : u64 ,
963
+ /// The value, in msat, of the payment after this hop's fee is deducted.
964
+ pub amt_to_forward : u64 ,
965
+ /// outgoing CLTV for the next hop
966
+ pub outgoing_cltv_value : u32 ,
967
+ /// onion packet for the next hop
968
+ pub onion_packet : msgs:: OnionPacket ,
969
+ }
970
+
971
+ /// Received payment, of either regular or blinded type
972
+ #[ derive( Debug ) ]
973
+ pub enum ReceivedPayment {
974
+ /// Regular (unblinded) payment
975
+ Regular {
976
+ /// payment_secret to authenticate sender to the receiver
977
+ payment_secret : Option < [ u8 ; 32 ] > ,
978
+ /// The total value, in msat, of the payment as received by the ultimate recipient
979
+ total_msat : Option < u64 > ,
980
+ /// custom payment metadata included in the payment
981
+ payment_metadata : Option < Vec < u8 > > ,
982
+ /// preimage used in spontaneous payment
983
+ keysend_preimage : Option < [ u8 ; 32 ] > ,
984
+ /// custom TLV records included in the payment
985
+ custom_tlvs : Vec < ( u64 , Vec < u8 > ) > ,
986
+ /// amount received
987
+ amt_msat : u64 ,
988
+ /// outgoing ctlv
989
+ outgoing_cltv_value : u32 ,
990
+ } ,
991
+ /// Blinded payment
992
+ Blinded {
993
+ /// amount received
994
+ amt_msat : u64 ,
995
+ /// amount received plus fees paid
996
+ total_msat : u64 ,
997
+ /// outgoing cltv
998
+ outgoing_cltv_value : u32 ,
999
+ /// Payment secret
1000
+ payment_secret : [ u8 ; 32 ] ,
1001
+ /// The maximum total CLTV that is acceptable when relaying a payment over this hop
1002
+ max_cltv_expiry : u32 ,
1003
+ /// The minimum value, in msat, that may be accepted by the node corresponding to this hop
1004
+ htlc_minimum_msat : u64 ,
1005
+ /// Blinding point from intro node
1006
+ intro_node_blinding_point : PublicKey ,
1007
+ }
1008
+ }
1009
+
1010
+ impl std:: convert:: TryFrom < msgs:: InboundOnionPayload > for ReceivedPayment {
1011
+ type Error = ( ) ;
1012
+ fn try_from ( pld : msgs:: InboundOnionPayload ) -> Result < Self , Self :: Error > {
1013
+ match pld {
1014
+ msgs:: InboundOnionPayload :: Forward { short_channel_id : _, amt_to_forward : _, outgoing_cltv_value : _ } => {
1015
+ Err ( ( ) )
1016
+ } ,
1017
+ msgs:: InboundOnionPayload :: Receive { payment_data, payment_metadata, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value } => {
1018
+ let ( payment_secret, total_msat) = match payment_data {
1019
+ Some ( p) => ( Some ( p. payment_secret . 0 ) , Some ( p. total_msat ) ) ,
1020
+ None => ( None , None ) ,
1021
+ } ;
1022
+ let keysend_preimage = keysend_preimage. map ( |p| p. 0 ) ;
1023
+ Ok ( Self :: Regular { payment_secret, total_msat, payment_metadata, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value } )
1024
+ } ,
1025
+ msgs:: InboundOnionPayload :: BlindedReceive { amt_msat, total_msat, outgoing_cltv_value, payment_secret, payment_constraints, intro_node_blinding_point } => {
1026
+ let payment_secret = payment_secret. 0 ;
1027
+ let max_cltv_expiry = payment_constraints. max_cltv_expiry ;
1028
+ let htlc_minimum_msat = payment_constraints. htlc_minimum_msat ;
1029
+ Ok ( Self :: Blinded { amt_msat, total_msat, outgoing_cltv_value, payment_secret, max_cltv_expiry, htlc_minimum_msat, intro_node_blinding_point } )
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+
1035
+ /// Received and decrypted onion payment, either of type Receive (for us), or Forward.
1036
+ #[ derive( Debug ) ]
1037
+ pub enum PeeledPayment {
1038
+ /// This onion payload was for us, not for forwarding to a next-hop.
1039
+ Receive ( ReceivedPayment ) ,
1040
+ /// This onion payload to be forwarded to next peer.
1041
+ Forward ( ForwardedPayment ) ,
1042
+ }
1043
+
1044
+ /// Unwrap one layer of an incoming HTLC, returning either or a received payment, or a another
1045
+ /// onion to forward.
1046
+ pub fn peel_payment_onion < NS : Deref > (
1047
+ onion : & msgs:: OnionPacket , payment_hash : PaymentHash , node_signer : & NS ,
1048
+ secp_ctx : & Secp256k1 < secp256k1:: All >
1049
+ ) -> Result < PeeledPayment , ( ) >
1050
+ where
1051
+ NS :: Target : NodeSigner ,
1052
+ {
1053
+ if onion. public_key . is_err ( ) {
1054
+ return Err ( ( ) ) ;
1055
+ }
1056
+ let shared_secret = node_signer
1057
+ . ecdh ( Recipient :: Node , & onion. public_key . unwrap ( ) , None )
1058
+ . unwrap ( )
1059
+ . secret_bytes ( ) ;
1060
+
1061
+ let hop = decode_next_payment_hop ( shared_secret, & onion. hop_data [ ..] , onion. hmac , payment_hash, node_signer) . map_err ( |_| ( ) ) ?;
1062
+ let peeled = match hop {
1063
+ Hop :: Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
1064
+ if let msgs:: InboundOnionPayload :: Forward { short_channel_id, amt_to_forward, outgoing_cltv_value} = next_hop_data {
1065
+
1066
+ let next_packet_pk = next_hop_pubkey ( secp_ctx, onion. public_key . unwrap ( ) , & shared_secret) ;
1067
+
1068
+ let onion_packet = msgs:: OnionPacket {
1069
+ version : 0 ,
1070
+ public_key : next_packet_pk,
1071
+ hop_data : new_packet_bytes,
1072
+ hmac : next_hop_hmac,
1073
+ } ;
1074
+ PeeledPayment :: Forward ( ForwardedPayment {
1075
+ short_channel_id,
1076
+ amt_to_forward,
1077
+ outgoing_cltv_value,
1078
+ onion_packet,
1079
+ } )
1080
+ } else {
1081
+ return Err ( ( ) ) ;
1082
+ }
1083
+ } ,
1084
+ Hop :: Receive ( inbound) => {
1085
+ let payload: ReceivedPayment = inbound. try_into ( ) . map_err ( |_| ( ) ) ?;
1086
+ PeeledPayment :: Receive ( payload)
1087
+ } ,
1088
+ } ;
1089
+ Ok ( peeled)
1090
+ }
1091
+
938
1092
pub ( crate ) fn decode_next_untagged_hop < T , R : ReadableArgs < T > , N : NextPacketBytes > ( shared_secret : [ u8 ; 32 ] , hop_data : & [ u8 ] , hmac_bytes : [ u8 ; 32 ] , read_args : T ) -> Result < ( R , Option < ( [ u8 ; 32 ] , N ) > ) , OnionDecodeErr > {
939
1093
decode_next_hop ( shared_secret, hop_data, hmac_bytes, None , read_args)
940
1094
}
@@ -1235,4 +1389,103 @@ mod tests {
1235
1389
writer. write_all ( & self . data [ ..] )
1236
1390
}
1237
1391
}
1392
+
1393
+ #[ test]
1394
+ fn create_and_peel_payment_onion ( ) {
1395
+ use crate :: ln:: channelmanager:: RecipientOnionFields ;
1396
+ use crate :: ln:: PaymentPreimage ;
1397
+ use std:: convert:: TryInto ;
1398
+ use super :: { create_payment_onion, peel_payment_onion} ;
1399
+ use super :: { Sha256 , Hash , PeeledPayment , ReceivedPayment } ;
1400
+
1401
+ let secp_ctx = Secp256k1 :: new ( ) ;
1402
+ let recipient_onion = RecipientOnionFields :: spontaneous_empty ( ) ;
1403
+ let session_priv_bytes = [ 42 ; 32 ] ;
1404
+ let session_priv = SecretKey :: from_slice ( & session_priv_bytes) . unwrap ( ) ;
1405
+ let amt_msat = 1000 ;
1406
+ let cur_height = 1000 ;
1407
+ let preimage_bytes = [ 43 ; 32 ] ;
1408
+ let preimage = PaymentPreimage ( preimage_bytes) ;
1409
+ let rhash = Sha256 :: hash ( & preimage_bytes) . to_vec ( ) ;
1410
+ let rhash_bytes: [ u8 ; 32 ] = rhash. try_into ( ) . unwrap ( ) ;
1411
+ let payment_hash = PaymentHash ( rhash_bytes) ;
1412
+ let prng_seed = [ 44 ; 32 ] ;
1413
+
1414
+ // let alice = make_keys_manager(&[1; 32]);
1415
+ let bob = make_keys_manager ( & [ 2 ; 32 ] ) ;
1416
+ let bob_pk = PublicKey :: from_secret_key ( & secp_ctx, & bob. get_node_secret_key ( ) ) ;
1417
+ let charlie = make_keys_manager ( & [ 3 ; 32 ] ) ;
1418
+ let charlie_pk = PublicKey :: from_secret_key ( & secp_ctx, & charlie. get_node_secret_key ( ) ) ;
1419
+
1420
+ // make a route alice -> bob -> charlie
1421
+ let bob_fee = 1 ;
1422
+ let recipient_amount = 999 ;
1423
+ let hops = vec ! [
1424
+ RouteHop {
1425
+ pubkey: bob_pk,
1426
+ fee_msat: bob_fee,
1427
+ cltv_expiry_delta: 0 ,
1428
+ short_channel_id: 1 ,
1429
+ node_features: NodeFeatures :: empty( ) ,
1430
+ channel_features: ChannelFeatures :: empty( ) ,
1431
+ maybe_announced_channel: false ,
1432
+ } ,
1433
+ RouteHop {
1434
+ pubkey: charlie_pk,
1435
+ fee_msat: recipient_amount,
1436
+ cltv_expiry_delta: 0 ,
1437
+ short_channel_id: 2 ,
1438
+ node_features: NodeFeatures :: empty( ) ,
1439
+ channel_features: ChannelFeatures :: empty( ) ,
1440
+ maybe_announced_channel: false ,
1441
+ }
1442
+ ] ;
1443
+ let path = Path {
1444
+ hops : hops,
1445
+ blinded_tail : None ,
1446
+ } ;
1447
+
1448
+ let ( _htlc_msat, _htlc_cltv, onion) = create_payment_onion (
1449
+ & secp_ctx, & path, & session_priv, amt_msat, recipient_onion, cur_height, payment_hash,
1450
+ Some ( preimage) , prng_seed
1451
+ ) . unwrap ( ) ;
1452
+
1453
+ // bob peels to find another onion
1454
+ let next_onion = match peel_payment_onion ( & onion, payment_hash, & & bob, & secp_ctx) . unwrap ( ) {
1455
+ PeeledPayment :: Receive ( _) => {
1456
+ panic ! ( "should not be a receive" ) ;
1457
+ } ,
1458
+ PeeledPayment :: Forward ( forwarded) => {
1459
+ forwarded. onion_packet
1460
+ } ,
1461
+ } ;
1462
+
1463
+ // charlie peels to find a received payment
1464
+ match peel_payment_onion ( & next_onion, payment_hash, & & charlie, & secp_ctx) . unwrap ( ) {
1465
+ PeeledPayment :: Receive ( received) => match received {
1466
+ ReceivedPayment :: Regular { amt_msat, keysend_preimage, ..} => {
1467
+ assert_eq ! ( amt_msat, recipient_amount, "wrong received amount" ) ;
1468
+ assert_eq ! ( Some ( preimage_bytes) , keysend_preimage, "wrong received preimage" ) ;
1469
+ } ,
1470
+ ReceivedPayment :: Blinded { ..} => {
1471
+ panic ! ( "should not be blinded" ) ;
1472
+ }
1473
+ } ,
1474
+ PeeledPayment :: Forward ( _) => {
1475
+ panic ! ( "should not be a receive" ) ;
1476
+ } ,
1477
+ } ;
1478
+
1479
+ }
1480
+
1481
+ fn make_keys_manager ( seed : & [ u8 ; 32 ] ) -> crate :: sign:: KeysManager {
1482
+ use crate :: sign:: KeysManager ;
1483
+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
1484
+ let start = SystemTime :: now ( ) ;
1485
+ let now = start
1486
+ . duration_since ( UNIX_EPOCH )
1487
+ . expect ( "Time went backwards" ) ;
1488
+ KeysManager :: new ( seed, now. as_secs ( ) , now. subsec_nanos ( ) )
1489
+ }
1490
+
1238
1491
}
0 commit comments