Author Archives: prscientist

About prscientist

Computer Scientist

Inspecting TLS traffic

Published / by prscientist

TLS traffic with Chrome and Wireshark

TLS traffic inspection on Ubuntu/Wireshark can be easily configured. For each TLS handshake the encryption keys need to be made available at the middle man. For this to run automatically we need two things: 1) activate the dumping of the (pre)master-secret and 2) Wireshark needs to know where to look.

Following steps have been tested on Ubuntu Noble Numbat 24.04, Google Chrome 133.0.6943.141(official build)(64-bit) and Wireshark 4.2.2:

  • add SSLKEYLOGFILE to the environment and start Chrome: export SSLKEYLOGFILE=/home/hiddenuser/.ssl-key.log && google-chrome
  • browse to some https:// URL and verify the keylog file is being updated
  • in Wireshark at the Edit->Preferences->Protocols->TLS under the (Pre)-Master-Secret log filename, use the above file “/home/hiddenuser/.ssl-key.log”
  • generate traffic and inspect it by adding to Wireshark a general filter “tls && (http || http2)”

TLS Keylog File

The .ssl-key.log file format – each line contains a separate secret composed of 3 values:

  • the label
    • identifies the type of secret
    • there can be multiple types, for ex: CLIENT_RANDOM, CLIENT_HANDSHAKE_TRAFFIC_SECRET, SERVER_HANDSHAKE_TRAFFIC_SECRET, CLIENT_TRAFFIC_SECRET_0, SERVER_TRAFFIC_SECRET_0, etc
  • client random
    • the string of random bytes generated on the client during the Client Hello part of the TLS handshake protocol
    • this is a 32 byte value represented as 64 hexa chars
    • is used as a key in order to differentiate which labels belong to which connection
  • secret
    • variable length hex value

As example take a look at this section from my .ssl-key.log where we can observe entries from three independent negociations:

CLIENT_TRAFFIC_SECRET_0 a32eb0704df85d2c8dfed2ecf721ed512d33da179732965c721dc4ba935e53f5 cdf1b007b92e8aa77da7091cb81f0fd75132c83eab85865bb6a76432cc9f959ab4712636271f506665b1dfd97a1f8ce8
SERVER_TRAFFIC_SECRET_0 a32eb0704df85d2c8dfed2ecf721ed512d33da179732965c721dc4ba935e53f5 0c1e810216b76f388aa9179b852fa2b1f935c2224f082d51801118362e28567199ea7802446ce9e9d802042f2a95a6d0
EXPORTER_SECRET a32eb0704df85d2c8dfed2ecf721ed512d33da179732965c721dc4ba935e53f5 45db7b3bc67a4c700863cb9dce62d38329239db3eade797ea8e990065bda14e6fdf1e2768bc5be2ff78fef916e74bcb0
CLIENT_HANDSHAKE_TRAFFIC_SECRET ed0a238a60e290cb3864a899818b496f4de2bc4d8f9489e90e047ec9b9e6465c cf668ae741f57c7c42d44d35a1d71c0ce888f947de3056741cf394cf7ccd919e9c36574ca20c76f9cd6db9f709943702
SERVER_HANDSHAKE_TRAFFIC_SECRET ed0a238a60e290cb3864a899818b496f4de2bc4d8f9489e90e047ec9b9e6465c 2a093a96dc61bca91d9710444202d471f7175ee427242e2e572f186dfdd8f4096fa9c6a77a4dfdb2806ce609267310c8
CLIENT_RANDOM c382a546c4c5f47961c208aefc57dfce8d09c1ba8d23ab2b297a269d961bc816 2ec13a3622f4c60fba03f565f6bd701a3765582b1344879ae25a978b316cd4c04b1ae0547b1b9f239781659695d6d0a8

TLS pre-master secret vs master secret

To establish a fully encrypted communication over TLS 1.2 here are the steps involved. Please note the role of the pre-master secret:

  • Client Hello – sends supported TLS version, supported ciphers, a client random string
  • Server Hello – sends server’s SSL certificate, server chosen cipher, a server random string
  • Authentication – client verifies server’s SSL certificate with the CA that issued it
  • Server Hello Done – sends a message to client to confirm that Server Hello has been completed
  • Client Key Exchange – client generates a pre-master secret, another random string. this is encrypted using the public key embedded in the received SSL certificate and is sent to the server
  • Private key used – server decrypts the pre-master secret using its private key
  • Session keys created – both client and server generate independently session keys from the: client random str, server random str and the pre-master secret. both should be the same
  • Client Ready – client sends a “finished” message encrypted with a session key
  • Server Ready – server sends a “finished” message encrypted with a session key
  • Handshake Finished – communication goes on with a symmetric encryption

So the all wanted pre-master secret is a random string generated on the client, shared with the server and lastly used to generate the master secret on both ends.

A Pseudo-Random Function (PRF) is then employed to calculate the master_secret = PRF(pre-master-secret, “Master-Secret”, ClientHello.random + ServerHello.random). In the end the master_secret is used on the client and on the server to generate the session key.

Having described the steps for the old TLS 1.2, with TLS 1.3 which nowdays is almost ubiquous, we can see the process is simplified / accelerated. Based on the info received during the Client Hello – a client random string and a client key share, the server generates the pre-master secret and even advances generating the master secret. During the Server Hello, the server sends back the server random string along with a server key share. This data is sufficient for the client to independently generate the pre-master secret – which as you see is not that random anymore, and will advance to generating the master secret. Such method works because each party agrees and openly shares a set of parameters along with a public key – carefully crafted using the aforementioned params – see the Diffie–Hellman key exchange and the Elliptic-curve Diffie–Hellman.

Depending on the TLS version running, entries in the .ssl-key.log might contain either the pre-master secret or the master secret. For ex. in case of TLS 1.2 the CLIENT_RANDOM type is used to identify the “master” secret for the connection.

References

https://wiki.wireshark.org/TLS#using-the-pre-master-secret
https://datatracker.ietf.org/doc/html/draft-ietf-tls-keylogfile
https://medium.com/@thesslstore/tls-1-3-handshake-taking-a-closer-look-11667ff92645
https://www.cryptologie.net/article/340/tls-pre-master-secrets-and-master-secrets
https://cabulous.medium.com/tls-1-2-andtls-1-3-handshake-walkthrough-4cfd0a798164
https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman

How to restore the Visual Studio Code build errors dialog

Published / by prscientist

The Visual Studio Code is a great tool which I use sometimes to write/debug code snippets. It’s got everything you’d want: it’s modern, free, has got cloud plugins, it’s well documented, etc.

For a full experience you can integrate it easily with build/debugging tools. That’s what I did with C++/MSYS64 then you hit CTRL+F5 and it snaps a new build right away 😀

Let’s say you are less than perfect and sometimes after a build you get some build errors.

A dialog pops up asking if you want to see the errors or simply “Debug anyway” which will take you in a debug session on the old executable. Not sure who would use that, especially since you hit CTRL+F5 (run without debugging) and not the F5 (start debugging)

Maybe that choice comes unexpected so you “Debug anyway” then tick the “Remember my choice in user settings”. Aaand that spells trouble :)) on new builds you’ll go auto-debug the old code, instead of some popup showing / clearly showing the Problems tab

To restore showing the dialog on future builds you need to go to:
File > Preferences > Settings, then search for the “On Task Errors” then simply change to “prompt”

Note, the above are valid at least with Visual Studio Code version 1.92.0

Keywords: VSCode, Visual Studio Code, show build popup, show build errors dialog, revert rember my choice

CAST-128 encryption in practice

Published / by prscientist

 

This symmetric-key block cipher comes in handy as it allows a variable key size of 40 to 128 bits and a block size of 64 bits. According to RFC2144 there is no difference between CAST-128 and CAST5, these are two names of a same thing.

 

Even if widely regarded unsafe, some of us still have reasons for using a smaller key. Other people should go for the full 128 bit key.

We will discuss how you encrypt a text with openssl and decrypt it from php, along with a couple of subtleties for the beginner crypto user. For this example we will use CAST-128 with a 64 bit key.

Common questions for block ciphers:

  • how does the block size impact the plaintext? which kind of padding is being applied pre-encryption? — depending on the params, openssl may use the PKCS#5 padding algorithm or in case of zero padding it may expect the plaintext to be pre-paded/have its length multiple of block length
  • is the PKCS#5 padding similar to PKCS#7? — “PKCS#5 padding is identical to PKCS#7 padding, except that it has only been defined for block ciphers that use a 64-bit (8-byte) block size. In practice the two can be used interchangeably.” Source: Padding (cryptography).
  • what initialization vector (iv) we use for CAST-128? — When we encode in CBC mode, “The iv is optional and defaults to all-zero.”. Source: RFC2144 

OpenSSL

  • Depending on your platform along with your openssl version, params might not be the same, here all been tested on a macOS Big Sur ver.11.4 with version OpenSSL 1.1.1i
  • To encrypt with a 64 bit key, which is a medium key length supported by CAST-128 please note, the openssl will be padding your key up to 128 bit. Zeros will be added. So if you call openssl with enc -K “ABCDABEFAABBCCDD” which is a 64 bit key, in reality key will be ABCDABEFAABBCCDD0000000000000000  
  • Make sure the input file does not contain any extra chars such as LF. Consider as input a file containing ANNABELLE in plain text
MacBook-Pro:~ alexandru$ openssl enc -K "ABCDABEFAABBCCDD" -cast -e -in input.txt -out output.base64 -iv 0000000000000000 -nosalt -base64 -p
hex string is too short, padding with zero bytes to length
key=ABCDABEFAABBCCDD0000000000000000
iv =0000000000000000

MacBook-Pro:~ alexandru$ cat output.base64
M11VwvXjPq5sWTrZr4KNDA==

PHP

  • From PHP are calling the openssl_decrypt and not the obsolete mcrypt_decrypt
  • Due to the OPENSSL_RAW_DATA we are preparing most params as binary, with the only exception: $method
  • The $decrypt_result will be plain text
$method = "CAST5-CBC";
$secret_key = hex2bin("ABCDABEFAABBCCDD"); //hex string transformed into binary

$encrypted_msg = "M11VwvXjPq5sWTrZr4KNDA=="; //note, this is base64
$raw_encrypted_msg = base64_decode($encrypted_msg);

$iv = hex2bin("0000000000000000"); //hex string transformed into binary

if (is_bool($decrypt_result = openssl_decrypt($raw_encrypted_msg, $method, $secret_key, OPENSSL_RAW_DATA, $iv)))
echo "FAILED!";
else
echo $decrypt_result;

Tricks

  • to find what kind of padding your openssl inserted on your plaintext: encrypt normally then decrypt adding the -nopad parameter, the PKCS#5 / PKCS#7 is NOT padding with zeros
openssl enc -K "ABCDABEFAABBCCDD" -cast -e -in input.txt -out output.base64 -iv 0000000000000000 -nosalt -base64
openssl enc -K "ABCDABEFAABBCCDD" -cast -d -in output.base64 -out output.dec -iv 0000000000000000 -nosalt -base64 -nopad

References

A Playstation 2 Story – Chapter 1, fixing the Power Supply

Published / by prscientist

WARNING: Unless you REALLY know what you’re doing, DON’T attempt fixing your Playstation power supply! The power board contains large capacitors which may deliver a deadly shock, also when the device is unplugged!

Short story:
– Playstation 2 Fat model no. SCPH-50004, input 240V
– Power supply module not delivering 12V to the motherboard. It was delivering 0V
– Went on taking voltage measurements at different points on the board, which sometimes triggered a discharge towards the negative, temporarily fixing the issue
– One capacitor turned out having a really large ESR and a large voltage loss
– Replacing this bad capacitor permanently fixed the issue

Long story:
Last Saturday while strolling through the flea market, some fairly looking console caught my eye. It was a fat PS2 with no warranty sticker. The seller was confident about it running just fine. He was arguing “my kids just paid 1500 RON (about 300 EUR) for a new console” while i was replying “yeah, that doesn’t mean this one’s working” :> I ended paying 30 RON (about 6 EUR) which makes it a true bargain! Of course I hoped it was working :))

At home, the first test and the console doesn’t power up! So i went disassembling it, dusting all components, case, cd-bay area. Isopropyl Alcohol is a great PCB cleaner, but don’t use it on plastic/rubber. There was a missing ribbon cable – connecting the controller unit to the motherboard and also, a cable connecting the cooler to its power supply. Interestingly the cooler fan was still in place.

Both missing parts can be bought online. That holds true for the power supply module, but attempting fixing it is more interesting

Things I tried:
– Went online looking for a power block schematic. Couldn’t find anything for the SCPH-50004 model, however there are fan-made schematics for other models.
– This is the best digest of schematics all of which seem to match the PS2 Power Source
– Also, note this schematic for the 90002

– None of the above schematics seemed to fully match my board

– 0V at CN2 so I started following where we loose power. The C1 condenser was getting DC as it was past the bridge rectifier, and its voltage was 300V
– Same voltage at primary side of transformer T1 at both pins 1 and 3 and at first this looked ok
– Later on, while probing Voltage with the negative probe at C1 negative pin, and the positive probe at different points on the board, sometimes, a discharge was happening and the power supply started delivering 11.9V at CN2
– The conditions for the discharge were never identical, but somewhere in the same area. One example was probing with the voltmeter the diode D1B cathode and C1 negative pin, right after which the circuit started working normally. That’s when transformer T1 pin 1 was still displaying 300V where pin 3 was displaying a variable voltage of 0V, 12V, 2V, 1V, 0V, 17V, 0V, 20V, etc. This looks like a capacitor not doing the job
– Instead of looking at ceramic capacitors which rarely fail, I went considering the electrolytic capacitors: C20 and C3. For that I employed my ESR meter, hoping to tell which was bad before any desoldering

ESR metering:
– As the capacitance goes down the ESR goes up

Faulty C3 tested off board

    – for the C20 capacitor

  • in circuit reading 89.79µF Vloss 7.4% ESR 1.5Ω
  • the replacement was 23.90µF Vloss 0.9% ESR 2.6Ω
  • off board it measured 22.49µF Vloss 1.2% ESR 0.65Ω
  • So this was a good capacitor! Since it was off the board I went of replacing it anyways
    – for the C3 capacitor

  • in circuit reading 133.3µF Vloss 15% ESR 35Ω
  • the replacement was 35.91µF Vloss 1.4% ESR 2.1Ω
  • off board was reading 31.68µF Vloss 13% ESR 69Ω
  • Given the abnormally high ESR not to mention the Voltage Loss, this is a faulty capacitor that needs replacement

Problem solved:

PS2 Power Source now delivering 12V to the motherboard

List of identified parts:
– Note, list is compiled based on original components in my SCPH-50004
– C2, ceramic capacitor, BC X7R 102K 1KV, note the X7R class of -55º to 125º, and the K capacitor tolerance of 10%
– C3, capacitor, 33µF 35V
– IC2, optocoupler, PC123
– C20, capacitor, 22µF 50V 105º
– C21, ceramic capacitor, X7R 471K 1KV, that’s a 470pF 1000V with capacitor tolerance of 10%
– C22, ceramic capacitor, X7R 471K 1KV
– ZD2, zenner diode, 15V
– ZD3, zenner diode, 18V
– NTC1, thermistor, SCK 103 330
– Q1, dual Schottky diode, MBR20H100CTG

Useful links:

No rocket science

Published / by prscientist

The Match Cord

Who wants to solve with me a rocket problem? All right 🙂 We might not be rocket scientists but we surely enjoy rocket and mountain problems, especially when they act as cover-up for some computer science subject.

In this case, for those of you seeking the simplest possible method there is a naive approach that can be written in a couple minutes 😉 We will not discuss that. Instead, we are interested in an optimal solution with linear time complexity.

Problem Description:

We are testing a new type of projectile which is launched in a fixed direction. Each rocket flies horizontally until it hits the ground, and remains there piling up. Launching happens from different heights so they hit the ground at different points.

As input you will receive two zero based arrays, A and B, each containing respectively M and N integers. Array A describes the lanscape in the direction the projectile is launched. Each element from A represents the height of the ground starting from the projectile launcher. Array B contains successive heights from where rockets are shot.

Let’s assume the launcher shoots a rocket from height H. If I is the smallest index with 0 < I < M and A[I] >= H, then the rocket falls at position I – 1 and increases ground level A[I – 1] with 1.

If there is no such I and launch height H > A[I] for all 0 <= I < M the rocket flies beyond horizon and does not affect any part of the lanscape. If H <= A[0] then the rocket ricochets away and again there is no effect on the result. You will have to write an algorithm to simulate the flight of rockets given A, B vectors of M and N sizes. The algorithm will produce a result array RA, which will contain the updated line of lanscape based on the initial landscape A and the shooting described through the B projectile launcher successive heights. Example:    M = 4; N = 8;    A[0] = 0; A[1] = 0; A[2] = 0; A[3] = 4;    B[0] = 1; B[1] = 1; B[2] = 0; B[3] = 6; B[4] = 1; B[5] = 2; B[6] = 3; B[7] = 2; Result:    RA[0] = 1; RA[1] = 2; RA[2] = 3; RA[3] = 4; Bounds:    M, N - integers [0..50000]    each element of A is an integer [0..2000000]    each element of B is an integer [0..2000000] Complexity concerns: - worst case time complexity should be O(M + N + H) - worst case space complexity should be O(M)

Discussion:

As we see from the time complexity O(M + N + H) a linear solution is expected. There cannot be any nested loops, recursion or other methods that would make it polynomial or worse. Linear sounds great but how?

Let’s do some logical connections. What we know or can be found easily:

• we know the current landscape configuration, a sequence of heights stored in array A

• based on it we can find the maximum landscape height MAXH

• maybe the landscape contains MAXH more than once, but we only care for the first “peak”

• side note. why we only care for the first peak. if the landscape did contain multiple positions having same height, there is no way for a flying rocket to reach the 2nd or other subsequent peak, without crushing into the first peak.

• we extend this search for all valid heights. so for each height h with 0 <= h <= MAXH we need to find the minimum landscape index MINL(h) = { i | h = A[i] and i is minimum }. • although it contains the maximal value of MAXH, certain landscape inputs might not contain an index for every other possible height in the range [0 .. MAXH] so there might exist such k with 0 <= k <= MAXH where MINL(k) is empty. this possibility obstructs us from using function MINL to forecast the first landscape index where a projectile is going to hit. To cover, we will define another function named MINLC: MINLC(h) = MINL(h), if MINL(h) is not ∅ OR MINLC(h) = smallest, nonempty MINL(h1), where h1 > h, if MINL(h) is ∅

• here is an example. the landscape array contains four positions:
    A[0] = 0, A[1] = 3, A[2] = 3, A[3] = 5.

The MAXH is 5, meaning that MINL contains the following values:

    MINL(0) = 0
    MINL(1) = ∅
    MINL(2) = ∅
    MINL(3) = 1
    MINL(4) = ∅
    MINL(5) = 3

MINLC will be equal to MINL for all non empty positions. For the rest:

MINLC(height value 1) = index value 1, because the index 1 in landscape array A contains the first non-empty value satisfying height value 3 > height value 1

    MINLC(1) = 1
    MINLC(2) = 1
    MINCL(4) = 3

• we should not forget that each rocket crushing into the ground falls at the previous landscape index increasing the local height. we will need to take into account such updates

• due to the MINLC function, for any launch height, we can find directly which is the landscape index where the rocket falls. all we have to do is iterate the B array, find the index where the rocket falls by applying MINLC, then increase ground level at that position.

Code:

• Note. This is a C99 solution focusing on readability rather than code length. Also, it can use better error logging or commenting. These aspects were not the purpose of this solution.

• At this point we achieve the worst case time complexity of O(M + M + H + N) which can be further optimized into O(M + H + N) by introducing some std::map to store the (height, ground index) pairs. This way we eliminate the need for finding the largest height, then allocating memory space. I will leave this small exercise to you 😀

 
struct Results 
{
    int * A1;
    int M;
};
 
struct Results shootingRockets(int A[], int M, int B[], int N)
{
    struct Results r;
    memset(&r, 0, sizeof(r));
 
    if (M < 1 || !A || !B)
        return r;
 
    if (N < 1)
    {
        r.A1 = A;
        r.M = M;
    }
 
    //find max terrain height
    int maxTerrainH = -1;
    int j = 0;
    for (j = 0; j < M; ++j)
    {
        if (A[j] > maxTerrainH)
            maxTerrainH = A[j];
    }
 
    //all rockets will fall before, or fly over
    if (maxTerrainH <= 0)
        return r;
 
    //we are using extra storage space to accomodate
    //the index of the first peak of certain height.
 
    //the heights array will be maxTerrainH + 1 to
    //react correctly to launches from height 0
 
    int heightsCount = maxTerrainH + 1;
 
    int *heights = (int *)malloc(heightsCount * sizeof(int));
    if (!heights)
    {
        return r;
    }
 
    memset(heights, -1, heightsCount * sizeof(int));
 
    //we are building the MINLC function:
 
    //First step. iterate landscape positions,
    //store in heights array, only those indexes
    //with peaks of heights we haven't seen before
 
    int max = -1;
    int k = 0;
    for (k = 0; k < M; ++k)
    {
        if (A[k] > max)
        {
            max = A[k];
            *(heights + max) = k;
        }
    }
 
    //Second step. Some positions are stil storing -1
    //These landscape heights are not accessible
    //at this point through dirrect shots. We need to
    //calculate their heights value based on surrounding
    //heights.
 
    for (k = heightsCount - 1; k > 0; --k)
    {
        if (*(heights + k - 1) == -1)
        {
            *(heights + k - 1 ) = *(heights + k);
        }
    }
 
    //iterate each launch height
 
    for (k = 0; k < N; ++k)
    {
        //rocket flies over horizon?
 
        if (B[k] > maxTerrainH)
        {
            continue;
        }
 
        //find where does it hit ground
 
        int whereItHits = *(heights + B[k]);
        int whereItFalls = whereItHits - 1;
 
        if (whereItFalls >= 0)
        {
            //increase ground level
            A[whereItFalls] += 1;
 
            //before, a rocket would fly over
            //now, due to the latest ground level increase,
            //hits right here. we have to update the heights array
 
            if (*(heights + A[whereItFalls]) > whereItFalls)
            {
                *(heights + A[whereItFalls]) = whereItFalls;
            }
        }
    }
 
    if (heights)
    {
        free(heights);
    }
 
    r.A1 = A;
    r.M = M;
 
    return r;
}

The monk and the mountain

Published / by prscientist / 1 Comment on The monk and the mountain

The other day, while talking to a friend he asked if I was up for a puzzle. As I always enjoy a good challenge I answered: what puzzle? Then he started telling and telling, where in the end there was this simple question. From the very start I had an answer but it was restraining the generality, therefore unacceptable. After a bit of analyzing, I have found something much better along with some pitfalls for the careless solver. In this article we will discuss the pitfalls and of course, the *solution* .

First, let’s have a look at the puzzle:

A monk starts one morning a journey from the base of the mountain to a monastery at the top. He leaves at 8am and gets there at 5pm. He spends night at the monastery and the next morning he climbs down retracing the route. He leaves at 8am from the top and arrives at the base at 5pm. Is there such moment (of the day) when he’ll be at same location in both days?

 

SPOILER WARNING> If you wish solving this puzzle independently stop reading here.

 
At a glance, the naive answer is – sure, it is possible as long as he’s going with constant speed, both days. The moment will be around noon, more precisely 12.30pm ( 8 + ( 17 – 8 ) / 2) at half distance. This answer induces a new parameter, the speed being constant which affects the question generality, therefore we might as well ignore it.

Google Chart

So what is the right answer? Let us read the problem again. Text seems to be straightforward: 8am at the base, goes walking with variable speed. Maybe he starts with great speed covering 6/10 of distance in just 1/3 of time, then for the last 4/10 incredibly slow, enjoying the scenery, consuming the remaining 2/3 of time. He’s reaching summit at 17. We can think in terms of functions. On the X we’re representing time from 0 to 9, where we add to 8am to obtain the absolute hour. On the Y axis we’re representing the distance from start from 0 to 10. The problem does not state the exact distance from base to summit. That’s not important.

Google Chart

On the next day he’s taking the same route but starting at 8am from the summit. Let us assume he’s going relatively slow, watching birds with binoculars or something. After 2/3 of time he’s covered just 1/10 of distance. When he realizes how late and how much more distance, knowing how mountains are not safe after nightfall, starts racing down. Back in the day the monk used to be athletic, doing mountain marathons so he’s reaching base at precisely 17.00.

All good so far. We have read most of the text, taking two extreme examples and representing them on such nice charts :). What about the question? It is suggesting somehow, no matter what variables, there should exist a same hour each day when monk’s location will be the same. How could it be? In the above examples, the monk is at very different locations at say, 10am – which is 1 hour offset from the start. And “start” means the first day close to the base, the next day close to the mountain top. Doesn’t this look like a valid counter-example, sufficient to answer the puzzle with “NO, it is impossible”? This is the first trap. Actually, no. The puzzle question asks whether there is such moment in time (if it exists) and not if every hour meets the criteria. Finding a certain hour where the criteria doesn’t fulfill is wrong. Instead of proving universal quantification we need to prove existential quantification.

It might be a good idea representing both ascending and descending functions on the same graph. For ex. let us name f the ascending function and g the descending function. Each function take x as elapsed time and produce y as distance from the start. Can you think of a condition for both functions to test the puzzle question? Yes, you’re right. We need to put the two in a system of equations:

y = f(x)
y = g(x)

Same x time of the day produces same y monk location. Let us have the ascending and descending functions drawn on a same graphic.


Google Chart


We see no intersections other than at 8am and at 17pm. But then we know it’s impossible for the monk to be in the same location. At 8am in the first day he’s at the base of the mountain, the next day he’s at the monastery. Wasn’t this graph supposed to show us the solution? Where is the error? …And this is how we find the 2nd trap :). Anybody not paying attention could fall for it. There is nothing wrong with having intersections at start and at finish. On Y axis we’re representing distance from the start. Situation where intersections have some other meaning — the monk does start at 8am (0 offset on X axis ) and he does reach destination 9 hours later.

The question is what we choose to represent on Y axis. To be meaningful for the puzzle-question, we should have represented absolute location. “..when he’ll be at same location in both days?” – same location can only be referred to as in absolute terms, or needs to be computed. We’re taking the easier option. The ascending function stays the same, he starts from 0 and reaches mountain top at location 10. We need to modify the descending function which given changes will start at location 10 and as time passes, reach location 0.


Google Chart


CONCLUSION> Just by watching the above graphic we understand some takeaways. The monk retraces his steps. The trail is uninterrupted. Continually, his current location is a place he has visited both days, only at different moments of the day. For each location, we compute a positive difference between the moments of the day he’s passed that location. Value range for this amount looks like a reversed bell. It’s maximum for locations close to base or summit — almost 9 hours. But as he’s walking towards midpoint, the amount is decreasing to a point where is zero. That’s the location/moment we’ve been searching for.

 
The answer is obvious now — YES.
 

Welcome

Published / by prscientist

Hi and welcome to The Lab,

You have reached a place where you might find answers if not a different way to question the world on various subjects. The Lab is the place to conduct experiments related, yet not limited to logic and logical reasoning, puzzles, mathematics and recreational mathematics, computer science, algorithms, programming, gaming, etc. I am Alex and I’ll be your guide to what I hope will prove to be a wonderful ride to the world, my world. A few words on my background. I have received a BSc degree in Computer Science from UAIC, last couple of years have been working for a number of companies in the industry. You can see my LinkedIn profile here. The content of this website is produced by me in random spare moments and you should ask for written permission before re-using it. External stuff I’ll be using will have expressively mentioned source, if you are the owner and want it removed, please leave a comment and I’ll get back to you asap!

 

Are we there yet?! [No, we’re just starting.. ]

The time is Short, so let’s GO 🙂

 

DISCLAIMER. The content of this website is provided as-is. Use it at your own risk. The author does not guarantee any information presented here is correct, valid or meaningful in any way. By surfing to this website/reading/learning/using any part of the content you agree to the fact that your are not offered any guarantees regarding any part of the content. The author cannot and will not be held responsible for any direct or collateral consequences resulting in the case of misuse.