Protocol checksum reverse engineering - math

I'm trying to reverse engineer a protocol's checksum. It seems to be a 4-bit nibble-based protocol.
The following is a binary representation of a packet in the protocol:
1000 0001 1000 0001 0000 0001 1111 0010 1010 : 1001
1000 0001 1000 0001 0000 0001 1111 0010 1011 : 1010
1000 0001 1000 0001 0000 0001 1111 0010 1100 : 1111
1000 0001 1000 0001 0000 0001 1111 0010 1101 : 0000
1000 0001 1000 0001 0000 0001 1111 0010 1110 : 1101
1000 0001 1000 0001 0000 0001 1111 0010 1111 : 1110
1000 0001 1000 0001 0000 0001 1111 0011 0000 : 0100
1000 0001 1000 0001 0000 0001 1111 0011 0001 : 0011
1000 0001 1000 0001 0000 0001 1111 0011 0010 : 0010
1000 0001 1000 0001 0000 0001 1111 0011 0011 : 0001
1000 0001 1000 0001 0000 0001 1111 0011 0100 : 1000
1000 0001 1000 0001 0000 0001 1111 0011 0101 : 0111
1000 0001 1000 0001 0000 0001 1111 0011 0110 : 0110
1000 0001 1000 0001 0000 0001 1111 0011 0111 : 0101
1000 0001 1000 0001 0000 0001 1111 0011 1000 : 1100
1000 0001 1000 0001 0000 0001 1111 0011 1001 : 1011
1000 0001 1000 0001 0000 0001 1111 0011 1010 : 1010
1000 0001 1000 0001 0000 0001 1111 0011 1011 : 1001
1000 0001 1000 0001 0000 0001 1111 0011 1100 : 0000
1000 0001 1000 0001 0000 0001 1111 0011 1110 : 1110
1000 0001 1000 0001 0000 0001 1111 0011 1111 : 1101
1000 0001 1000 0001 0000 0001 1111 0100 0000 : 0101
1000 0001 1000 0001 0000 0001 1111 0100 0001 : 0110
1000 0001 1000 0001 0000 0001 1111 0100 0010 : 0111
1000 0001 1000 0001 0000 0001 1111 0100 0011 : 1000
1000 0001 1000 0001 0000 0001 1111 0100 0100 : 0001
1000 0001 1000 0001 0000 0001 1111 0100 0101 : 0010
1000 0001 1000 0001 0000 0001 1111 0100 0110 : 0011
1000 0001 1000 0001 0000 0001 1111 0100 0111 : 0100
The last nibble (after the ":") is some sort of checksum. I can't figure out how it's calculated. I'm not even sure if it takes all previous fields into account. Most (if not all) of the other 36 bits are part of a simple incrementing counter.
If anyone can help figure out what the algorithm used to calculate the csum, that would be greatly appreciated.
Tom

I figured it out, with the help from an anonymous person on IRC. Turns out it wasn't the full packet, there were more bits preceding it. After that it's a simple XOR of all values plus one mod 16.

Related

A method for "deciphering" hex data from Salto's Mifare 1k card

I decided to investigate a bit a personal (1k Mifare) salto card. Neither getting the keys nor copying it were hard but now I take great pains "understanding" the hex I got from the card. As in previous questions I get gibberish when trying to convert the hex to ascii. Here are the blocks.
**Sector 0 (MAD etc.)**
040b b882 4d53 8188 4400 c820 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ffff ffff ffff ff07 8069 ffff ffff ffff
**Sector 1 (looks empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ffff ffff ffff ff07 8069 ffff ffff ffff
**Sector 2 (empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ffff ffff ffff ff07 8069 ffff ffff ffff
**Sector 3 (looks empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ffff ffff ffff ff07 8069 ffff ffff ffff
**Sector 4 (empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ffff ffff ffff ff07 8069 ffff ffff ffff
**Sector 5 (Application?)**
676e 14a3 ebb3 d6cf a172 2cb1 9ce0 79b4
6d7a 4ce8 0aa7 f716 5202 c2a0 8ce7 16b0
afd9 f931 6d76 6a30 349d 6ac9 61b3 c6e1
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 6 (Application?)**
2502 64f1 7c6e 1847 9680 a109 cabd dcea
083f 2f5a 503a 4196 bd3b 339b aced 8313
427f fe27 bc5c 5ba0 eae0 3eb8 c8eb e7b7
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 7 (Application?)**
7036 d4f9 dbf0 7bc4 a160 da23 e8c1 846a
d898 0955 82b2 16c5 2e3b 173c bff1 0f80
4d62 3096 7d27 8ba7 0c7c aa13 6131 82e4
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 8 (Application?)**
8f1e ca63 1b1f e526 dd50 ecf8 7737 92b4
9001 dd29 24f3 aae7 2581 8b61 0ba2 243c
e84c e706 7b49 b63e 971f d9ce be67 f44d
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 9 (Application? Very few data)**
0000 0000 0000 0000 0000 0000 0000 0000
5401 b42a 8185 d6e6 0000 0000 0000 0000
0018 e700 0000 0000 0000 0000 0000 0000
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 10 (Empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 11 (Empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 12 (Empty)**
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 13 (Application?)**
4600 f441 f951 93f9 77fc aa81 c3ff ab16
8ba5 7bbd 72b2 5835 929f 2228 5e79 34af
db3c 5d39 2d1c ec00 0000 0000 0000 0000
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 14 (Application?)**
bf09 00e6 0040 0018 0000 0000 f100 0000
0043 bc84 c36e d9e1 e31e b9b4 4034 43b2
36f0 a4a2 812b d6ca a577 55fb b892 6a61
6a19 87c4 0a21 f78f 005a 7f33 625b c129
**Sector 15 (Application?)**
e0ff 0000 0048 ef48 1f00 ffff ffb7 10b7
ff81 a900 1002 00c0 0000 0000 0000 0000
ffff 0ef1 8190 8705 7909 18d5 f97f 64ca
6a19 87c4 0a21 f78f 005a 7f33 625b c129
Is there any efficient way to convert the "non-trivial" data stored in the dump to "meaningful human-readable" data? For clear reasons Salto doesn't publish their documentation. I know for instance the card should not pass from some date in 2022 but looking for 22 wasn't meaningful neither in hex nor in ascii.

Is there any way to run a vector in checkluhn package?

I try to run the following code:
library(checkLuhn)
library(gsheet)
data<-gsheet2tbl("https://docs.google.com/spreadsheets/d/145Wowgp6NXmcj-IqqKfZ-2B2aKwAOzZ1VuCjxAq7WeM/edit?usp=sharing")
df <- data.frame(Card = character(),
Active = character(),
issuer =character())
for (i in 1: nrow(data))
{
card <- data[i,2]
active <- checkLuhn(card)
issuer <- issuer(card)
df = rbind(df, data.frame(Card = card, Active = active, Issuer =issuer, stringsAsFactors = FALSE))
}
But it is showing the following error:
Error in data.frame(Card = card, Active = active, Issuer = issuer, stringsAsFactors = FALSE) :
arguments imply differing number of rows: 1, 0
Can anyone help me please?
The issue seems to be with issuer which returns logical FALSE if there is none or else return a two column tibble. We could check the output type and make changes
library(purrr)
library(checkLuhn)
library(gsheet)
map_dfr(data$Number, ~ {
active <- checkLuhn(.x)
issuer <- issuer(.x)['issuer']
if(is.logical(issuer)) issuer <- tibble(issuer= NA_character_)
tibble(card = .x, active, issuer)
})
-output
# A tibble: 18 × 3
card active issuer
<chr> <lgl> <chr>
1 378 2822 4631 0005 TRUE American Express
2 371 4496 3539 8431 TRUE American Express
3 378 7344 9367 1000 TRUE American Express
4 5610 5910 8101 8250 TRUE Bankcard
5 5610 5910 8101 8250 TRUE Maestro
6 30 5693 0902 5904 TRUE Diners Club Carte Blanche
7 6011 1111 1111 1110 FALSE <NA>
8 6011 0009 9013 9420 FALSE <NA>
9 3530 1113 3330 0000 TRUE JCB
10 3566 0020 2036 0500 FALSE <NA>
11 5555 5555 5555 4440 FALSE <NA>
12 5105 1051 0510 5100 TRUE MasterCard
13 4111 1111 1111 1110 FALSE <NA>
14 4012 8888 8888 1880 FALSE <NA>
15 4 2222 2222 2222 TRUE Visa
16 760 0924 4561 FALSE <NA>
17 5019 7170 1010 3740 FALSE <NA>
18 6331 1019 9999 0010 FALSE <NA>
Or using the OP's code
df <- data.frame(Card = character(),
Active = character(),
Issuer =character())
for (i in 1:nrow(data))
{
card <- data[[2]][i]
active <- checkLuhn(card)
issuer <- issuer(card);
if(NROW(issuer) == 0 |is.logical(issuer)) {
issuer <- NA_character_
}else {
issuer <- issuer$issuer }
df <- rbind(df, data.frame(Card = card,
Active = active, Issuer =issuer, stringsAsFactors = FALSE))
}
-output
df
Card Active Issuer
1 378 2822 4631 0005 TRUE American Express
2 371 4496 3539 8431 TRUE American Express
3 378 7344 9367 1000 TRUE American Express
4 5610 5910 8101 8250 TRUE Bankcard
5 5610 5910 8101 8250 TRUE Maestro
6 30 5693 0902 5904 TRUE Diners Club Carte Blanche
7 38 5200 0002 3237 TRUE <NA>
8 6011 1111 1111 1110 FALSE <NA>
9 6011 0009 9013 9420 FALSE <NA>
10 3530 1113 3330 0000 TRUE JCB
11 3566 0020 2036 0500 FALSE <NA>
12 5555 5555 5555 4440 FALSE <NA>
13 5105 1051 0510 5100 TRUE MasterCard
14 4111 1111 1111 1110 FALSE <NA>
15 4012 8888 8888 1880 FALSE <NA>
16 4 2222 2222 2222 TRUE Visa
17 760 0924 4561 FALSE <NA>
18 5019 7170 1010 3740 FALSE <NA>
19 6331 1019 9999 0010 FALSE <NA>

Is there a TCP protocol violation causing "TCP connection lost" in these packets?

I have narrowed down a failure in communications to the following exchange. I can see the TCP establishment SYN, SYN/ACK, and ACK packets starting at packet #74. 22ms later, the connection is reported lost (very near the PSH packet #77) and I can't understand why. Is it ACKing the wrong SEQ? Comms are over a PLC link if it matters. The .6232 address belongs to my side of the link.
Many thanks in advance.
The evidence:
An EVSE communications controller (whose code I am not privileged to see) reports the following sequence of events:
[16/11/23_13:38:37:606] [Message] Sdp request successfully received and checked!
[16/11/23_13:38:37:797] [Message] TCP connection established ...
[16/11/23_13:38:37:801] [Message] Expected next Request: SupportedAppProtocol
[16/11/23_13:38:37:819] [Message] TCP connection lost ...
with these packets tcpdump'ed from the same EVSE's network:
#71 13:38:37.603416 IP6 fe80::201:87ff:fe05:2cbf > ff02::1:ff62:6232: ICMP6, neighbor solicitation, who has fe80::201:1ff:fe62:6232, length 32
0x0000: 3333 ff62 6232 0001 8705 2cbf 86dd 6000 33.bb2....,...`.
0x0010: 0000 0020 3aff fe80 0000 0000 0000 0201 ....:...........
0x0020: 87ff fe05 2cbf ff02 0000 0000 0000 0000 ....,...........
0x0030: 0001 ff62 6232 8700 4ce8 0000 0000 fe80 ...bb2..L.......
0x0040: 0000 0000 0000 0201 01ff fe62 6232 0101 ...........bb2..
0x0050: 0001 8705 2cbf ....,.
#72 13:38:37.620216 IP6 fe80::201:1ff:fe62:6232 > fe80::201:87ff:fe05:2cbf: ICMP6, neighbor advertisement, tgt is fe80::201:1ff:fe62:6232, length 32
0x0000: 0001 8705 2cbf 0001 0162 6232 86dd 6000 ....,....bb2..`.
0x0010: 0000 0020 3aff fe80 0000 0000 0000 0201 ....:...........
0x0020: 01ff fe62 6232 fe80 0000 0000 0000 0201 ...bb2..........
0x0030: 87ff fe05 2cbf 8800 389b 6000 0000 fe80 ....,...8.`.....
0x0040: 0000 0000 0000 0201 01ff fe62 6232 0201 ...........bb2..
0x0050: 0001 0162 6232 ...bb2
#73 13:38:37.620431 IP6 fe80::201:87ff:fe05:2cbf.15118 > fe80::201:1ff:fe62:6232.56978: UDP, length 28
0x0000: 0001 0162 6232 0001 8705 2cbf 86dd 6000 ...bb2....,...`.
0x0010: 0000 0024 1140 fe80 0000 0000 0000 0201 ...$.#..........
0x0020: 87ff fe05 2cbf fe80 0000 0000 0000 0201 ....,...........
0x0030: 01ff fe62 6232 3b0e de92 0024 ac61 01fe ...bb2;....$.a..
0x0040: 9001 0000 0014 fe80 0000 0000 0000 0201 ................
0x0050: 87ff fe05 2cbf cdec 1000 ....,.....
#74 13:38:37.784028 IP6 fe80::201:1ff:fe62:6232.56056 > fe80::201:87ff:fe05:2cbf.52716: Flags [S], seq 7266836, win 3107, options [mss 1440], length 0
0x0000: 0001 8705 2cbf 0001 0162 6232 86dd 6000 ....,....bb2..`.
0x0010: 0000 0018 06ff fe80 0000 0000 0000 0201 ................
0x0020: 01ff fe62 6232 fe80 0000 0000 0000 0201 ...bb2..........
0x0030: 87ff fe05 2cbf daf8 cdec 006e e214 0000 ....,......n....
0x0040: 0000 6002 0c23 ea52 0000 0204 05a0 ..`..#.R......
#75 13:38:37.784415 IP6 fe80::201:87ff:fe05:2cbf.52716 > fe80::201:1ff:fe62:6232.56056: Flags [S.], seq 206804358, ack 7266837, win 14400, options [mss 1440], length 0
0x0000: 0001 0162 6232 0001 8705 2cbf 86dd 6000 ...bb2....,...`.
0x0010: 0000 0018 0640 fe80 0000 0000 0000 0201 .....#..........
0x0020: 87ff fe05 2cbf fe80 0000 0000 0000 0201 ....,...........
0x0030: 01ff fe62 6232 cdec daf8 0c53 9586 006e ...bb2.....S...n
0x0040: e215 6012 3840 1c4b 0000 0204 05a0 ..`.8#.K......
#76 13:38:37.794237 IP6 fe80::201:1ff:fe62:6232.56056 > fe80::201:87ff:fe05:2cbf.52716: Flags [.], ack 1, win 3107, length 0
0x0000: 0001 8705 2cbf 0001 0162 6232 86dd 6000 ....,....bb2..`.
0x0010: 0000 0014 06ff fe80 0000 0000 0000 0201 ................
0x0020: 01ff fe62 6232 fe80 0000 0000 0000 0201 ...bb2..........
0x0030: 87ff fe05 2cbf daf8 cdec 006e e215 0c53 ....,......n...S
0x0040: 9587 5010 0c23 6011 0000 ..P..#`...
#77 13:38:37.810215 IP6 fe80::201:1ff:fe62:6232.56056 > fe80::201:87ff:fe05:2cbf.52716: Flags [P.], seq 1:18, ack 1, win 3107, length 17
0x0000: 0001 8705 2cbf 0001 0162 6232 86dd 6000 ....,....bb2..`.
0x0010: 0000 0025 06ff fe80 0000 0000 0000 0201 ...%............
0x0020: 01ff fe62 6232 fe80 0000 0000 0000 0201 ...bb2..........
0x0030: 87ff fe05 2cbf daf8 cdec 006e e215 0c53 ....,......n...S
0x0040: 9587 5018 0c23 ebbc 0000 01fe 8001 0000 ..P..#..........
0x0050: 0009 809a 0010 1108 4080 20 ........#..
#78 13:38:37.810533 IP6 fe80::201:87ff:fe05:2cbf.52716 > fe80::201:1ff:fe62:6232.56056: Flags [.], ack 18, win 14400, length 0
0x0000: 0001 0162 6232 0001 8705 2cbf 86dd 6000 ...bb2....,...`.
0x0010: 0000 0014 0640 fe80 0000 0000 0000 0201 .....#..........
0x0020: 87ff fe05 2cbf fe80 0000 0000 0000 0201 ....,...........
0x0030: 01ff fe62 6232 cdec daf8 0c53 9587 006e ...bb2.....S...n
0x0040: e226 5010 3840 33e3 0000 .&P.8#3...
#79 13:38:37.814004 IP6 fe80::201:1ff:fe62:6232.56056 > fe80::201:87ff:fe05:2cbf.52716: Flags [.], ack 1, win 3107, length 0
0x0000: 0001 8705 2cbf 0001 0162 6232 86dd 6000 ....,....bb2..`.
0x0010: 0000 0014 06ff fe80 0000 0000 0000 0201 ................
0x0020: 01ff fe62 6232 fe80 0000 0000 0000 0201 ...bb2..........
0x0030: 87ff fe05 2cbf daf8 cdec 006e e215 0c53 ....,......n...S
0x0040: 9587 5010 0c23 6011 0000 ..P..#`...
#80 13:38:37.814310 IP6 fe80::201:87ff:fe05:2cbf.52716 > fe80::201:1ff:fe62:6232.56056: Flags [.], ack 18, win 14400, length 0
0x0000: 0001 0162 6232 0001 8705 2cbf 86dd 6000 ...bb2....,...`.
0x0010: 0000 0014 0640 fe80 0000 0000 0000 0201 .....#..........
0x0020: 87ff fe05 2cbf fe80 0000 0000 0000 0201 ....,...........
0x0030: 01ff fe62 6232 cdec daf8 0c53 9587 006e ...bb2.....S...n
0x0040: e226 5010 3840 33e3 0000 .&P.8#3...
#81 13:38:37.817695 IP6 fe80::201:87ff:fe05:2cbf.52716 > fe80::201:1ff:fe62:6232.56056: Flags [F.], seq 1, ack 18, win 14400, length 0
0x0000: 0001 0162 6232 0001 8705 2cbf 86dd 6000 ...bb2....,...`.
0x0010: 0000 0014 0640 fe80 0000 0000 0000 0201 .....#..........
0x0020: 87ff fe05 2cbf fe80 0000 0000 0000 0201 ....,...........
0x0030: 01ff fe62 6232 cdec daf8 0c53 9587 006e ...bb2.....S...n
0x0040: e226 5011 3840 33e2 0000 .&P.8#3...
The real reason for the communications termination was that the network management key on the powerline communications controller was reset and the link dropped. Nothing to do with the comms, which is why they were not appearing in the Wireshark log.
The one packet that was sent was a CableCheck.REQ which the EVSE was not prepared for. (The correct packet should have been the SupportedAppProtocol.REQ as indicated by the EVSE log.)

In R: Want to find all "subvectors" with a specific length (9) from a large vector (length 300) , such that the elements sum to a given value

I'd like to find a way to list all the subvectors from the vector of salaries below, with the requirement that their sum lies between 54,000 and 55,000. I've tried using this method in C, but it takes way too long...I think because it finds the vectors before applying the limits (54,000 < sum(vector) < 55,000). Is there a way to improve on this, and preferably do it in R?
I've asked a friend about this, and he suggests developing a method to apply the sum limits as you go; because otherwise, the program would have to find (300 C 9) ~ 4.8 x 10^16 combinations.
Thanks!
Here's the list of salaries:
Salary
10800
9800
9600
9600
9500
9100
8800
8800
8700
8600
8600
8600
8600
8300
8200
8200
8100
8100
8100
8100
8000
7900
7600
7500
7500
7500
7400
7300
7300
7300
7200
7100
7100
7100
7000
6900
6900
6900
6800
6800
6800
6800
6700
6700
6600
6600
6600
6500
6500
6500
6500
6500
6400
6300
6300
6300
6200
6200
6100
6000
6000
6000
6000
5900
5900
5900
5800
5800
5800
5800
5800
5700
5700
5700
5600
5600
5600
5600
5600
5500
5500
5500
5400
5400
5400
5400
5400
5300
5200
5200
5200
5200
5200
5200
5200
5200
5200
5200
5100
5100
5100
5100
5000
5000
5000
5000
5000
5000
5000
5000
5000
5000
5000
5000
4900
4900
4800
4800
4800
4800
4800
4700
4700
4700
4700
4700
4700
4600
4600
4600
4500
4500
4500
4500
4500
4400
4400
4400
4400
4300
4300
4300
4300
4300
4300
4200
4200
4200
4200
4200
4200
4200
4100
4100
4100
4100
4100
4100
4000
4000
4000
4000
4000
4000
4000
4000
3900
3900
3900
3900
3900
3900
3900
3800
3800
3800
3800
3800
3800
3800
3800
3700
3700
3700
3700
3700
3700
3600
3600
3600
3600
3600
3600
3600
3600
3600
3600
3600
3600
3500
3500
3500
3500
3500
3500
3500
3500
3500
3500
3500
3500
3500
3500
3400
3400
3400
3400
3400
3400
3400
3400
3400
3400
3400
3400
3400
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3300
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3200
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3100
3000
3000
3000
3000
3000
3000
3000
3000
3000
3000
3000
3000
3000
3000
A bit of a belated response, but it might still be useful to somebody.
The idea is to generate all possible subvectors. Since the length of the vector is 320, there is 1 subvector of length 320, 2 subvectors of length 319, 3 subvectors of length 318, ..., and 320 subvectors of length 1. (Note these subvectors are not necessarily unique.) The number of possible subvectors is therefore "only" 321*320/2 = 51360.
Given the above, and assuming x <- c(10800, 9800, 9600, 9600, ..., 3000), the solution should be fairly self-explanatory:
# All possible start and end positions of subvectors
subvectors <- expand.grid(start=1:length(x), end=1:length(x))
# Of course, start must come before end
subvectors <- subvectors[subvectors$start <= subvectors$end, ]
# All possible subvectors
subvectors$values <- apply(subvectors, MARGIN=1, function(r) x[r[1]:r[2]])
# Subvector lengths (for convenience)
subvectors$length <- sapply(subvectors$values, length)
# Subvector sums
subvectors$sum <- sapply(subvectors$values, sum)
# All subvectors that satisfy the constraint
solutions <- subvectors[subvectors$sum >= 53000 & subvectors$sum <= 54000, ]
There are 65 solutions, with lengths ranging from 6 to 17.
Unlike the C solution mentioned above, this is more of a brute force method (O(n3)?), but it's simple enough and still takes just 1 second to run.

Time series data manipulation

I've had this problem before, but I didn't write down the solution, so now I'm in trouble again!
I have a dataframe like the following:
Date Product Qty Income
201001 0001 1000 2000
201002 0001 1500 3000
201003 0001 1200 2400
.
.
201001 0002 3500 2000
201002 0002 3200 1900
201003 0002 3100 1850
In words, I have one line for each combination of Date/Product, and the information of Quantity and Income for each combination.
I want to rearrange this dataframe so it looks like the following:
Date Qty.0001 Income.0001 Qty.0002 Income.0002
201001 1000 2000 3500 2000
201002 1500 3000 3200 1900
201003 1200 2400 3100 1850
In words, I want to have one line for each date, and one column for each combination of Product/Information(Qty, Income).
How can I achieve this? Thanks in advance!
Use reshape:
reshape(x,idvar="Date",timevar="Product",direction="wide")
Date Qty.0001 Income.0001 Qty.0002 Income.0002
1 201001 1000 2000 3500 2000
2 201002 1500 3000 3200 1900
3 201003 1200 2400 3100 1850

Resources