Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Inconsistent...

948 views
Skip to first unread message

Chris M. Thomasson

unread,
Oct 30, 2023, 5:01:52 PM10/30/23
to
This has to be undefined behavior. Check it out:

Here is my C code for a fun toy experimental fractal:

https://pastebin.com/raw/fcV5YiJH
(raw link to text...)

The cpack is different on the two different compilers. Oh, that is
always fun! Interesting. Here are some screenshots:

Online:

https://i.ibb.co/7n0wdWv/image.png

Notice cpack at 756768?

And on MSVC ver: 4.8.09032:

https://i.ibb.co/Pj0QZLf/image.png

cpack is at 95375807?

Interesting!

When you get some free time, can you compile and run my C code and
report the output? Thanks everybody.

:^)

Chris M. Thomasson

unread,
Oct 30, 2023, 5:11:54 PM10/30/23
to
Fwiw, here is an online version of it:

http://funwithfractals.atspace.cc/ffe/

Chris M. Thomasson

unread,
Oct 30, 2023, 5:30:23 PM10/30/23
to
On 10/30/2023 2:01 PM, Chris M. Thomasson wrote:
> This has to be undefined behavior. Check it out:
>
> Here is my C code for a fun toy experimental fractal:
>
> https://pastebin.com/raw/fcV5YiJH
> (raw link to text...)
>
> The cpack is different on the two different compilers. Oh, that is
> always fun! Interesting. Here are some screenshots:
>
> Online:
>
> https://i.ibb.co/7n0wdWv/image.png
>
> Notice cpack at 756768?
[...]

This is a little bugger!

main.c: In function ‘ct_ffe_gen_private_key’:
main.c:358:22: warning: format ‘%u’ expects argument of type ‘unsigned
int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
358 | printf("cpack = %u\r\n", cpack);

Richard Harnden

unread,
Oct 30, 2023, 6:02:06 PM10/30/23
to
That's just %lu, surely?

Do you need all those \r\n's? Doesn't the end of line conversion happen
automatically?

Chris M. Thomasson

unread,
Oct 30, 2023, 6:09:38 PM10/30/23
to
Yes. However, I am still getting different cpad results on two different
compilers. So, I need to find some time today or tommorrow to address that.


> Do you need all those \r\n's?  Doesn't the end of line conversion happen
> automatically?

Well, now that I think about this older code, I had HTTP protocol on the
mind during quickly fleshing it out. \r\n\r\n

bart

unread,
Oct 30, 2023, 7:22:49 PM10/30/23
to
I tweaked the source code (used explicit assignment to fields of some
structs) to be able to use my compilers.

Then I tried these compilers:

gcc 13.2.0 - this worked. (I assume it is supposed to show some
plaintext, encrypted text starting "fog.IiQ' U'?zDjP))v$oN)?z<xT
CAPNKUfB...", then the identical plaintext)

tcc - failed. The encrypted text started
"xy,$}lu~@NM*a%^z1YA+'N@9yrV]E...", and the decrypted was:
"dEjtkuXVjq5*uzqpWXE6tkzXVjq5czuqpWXE!t9zX\j35czu30/XE!tkuX\!qocuu3pWXEjtkzXVj3oczuq4WXE!0
kz.Vjqocuu3p/TEj0ku.Vj31cuz3pWXEjtkzXVj3o*uzq4W."

gcc/clang on rextester.com - passed (they share the same encrypted text;
it is different from gcc on my Windows machine, but matches that of gcc
under WSL on my machine.).

mcc (my new compiler) - passed, encrypted text matches gcc's.

bcc (my old compiler) - failed, encrypted text started
"z\n:`#-}9tYq,VcI?4aHN_rgCXhy&A'/:am..."

lccwin32 - the result was ... interesting. The decrypted text matched
the original exactly, which is good. But the encrypted text was
"AAAAAAAAAAAAAAAAA...".

I noticed it uses floating point and sin/cos functions. If I change
double to float, the ones that work still work, but the encrypted data
is different between mcc and gcc. The ones that don't work still don't.

Note: I ran the program in your first link, where the input data is
repetitions of your name. I couldn't see any relevance to your posted
screen shots.

bart

unread,
Oct 30, 2023, 7:45:02 PM10/30/23
to
On 30/10/2023 23:22, bart wrote:
> On 30/10/2023 21:01, Chris M. Thomasson wrote:

> gcc/clang on rextester.com - passed (they share the same encrypted text;
> it is different from gcc on my Windows machine, but matches that of gcc
> under WSL on my machine.).

Your (CMT's) code uses 'long' which is 32 bits on Windows and likely 64
bits on Linux.

If I change the type to 'u64', then the encrypted data now matches
between Windows and the presumably Linux system used on rextester.com.

Using float, Windows/Linux gcc/clang encrypted data still match.

Only between gcc/mcc using float is the encrypted data different.

I'll have a look to tomorrow at how practical it is to figure out what's
going on.

Ben Bacarisse

unread,
Oct 30, 2023, 7:52:55 PM10/30/23
to
"Chris M. Thomasson" <chris.m.t...@gmail.com> writes:

> This has to be undefined behavior. Check it out:
>
> Here is my C code for a fun toy experimental fractal:
>
> https://pastebin.com/raw/fcV5YiJH
> (raw link to text...)

Ask your compiler for the maximum number of warnings and you should see
lots. For some reason you are mixing types in a peculiar way, and since
some of those types often have different sizes you will get different
arithmetic results on different systems.

> The cpack is different on the two different compilers. Oh, that is always
> fun!

You need to decide what integer types you really want.

> When you get some free time, can you compile and run my C code and report
> the output? Thanks everybody.

What will you learn from that? You would be better off asking for the
warnings we get so you can fix the bugs.

--
Ben.

bart

unread,
Oct 30, 2023, 10:06:09 PM10/30/23
to
On 30/10/2023 23:22, bart wrote:
Regarding tcc, a few things differ internally, but I think one clue is here:

#define CT_MBROT_ABET_LOOKUP(mp_char) \
((strchr(CT_MBROT_ABET, (mp_char))) - CT_MBROT_ABET)

This is effectively doing the following (to get an offset into the string?):

str("ABC", c) - "ABC";

It is assuming that both string literals have the same address. Clearly
on Tiny C they don't!

If I move that string into a variable, then Tcc starts to work. So does
bcc. lccwin32 still has a problem.

Ben Bacarisse

unread,
Oct 31, 2023, 7:33:25 AM10/31/23
to
This is an unwarranted assumption.

But the result is also undefined when mp_char does not occur in the
string which can happen for two printable ASCII characters.

Chris, you should test your code more thoroughly.

> If I move that string into a variable, then Tcc starts to work. So does
> bcc.

Saying that tcc starts to work when you fix the bug suggests that tcc
was not working before, but it's the code that was not working. tcc
(and presumably bcc) were working fine all along.

> lccwin32 still has a problem.

What's the problem? Are you sure it's lccwin32 and not the source code
that has the problem?

--
Ben.

bart

unread,
Oct 31, 2023, 10:17:11 AM10/31/23
to
[Reposting as the original reply seems to have vanished, but it may
reappear]
When I say that compiler X has a problem, obviously I mean that the
program built with X shows an error. That is, the results are incorrect.

I'm not suggesting the compilers are at fault, although that is a
possibility especially with bcc (however, see below).

Probably this is not what Chris had in mind when he mentioned
inconsistency. But finding out why those compilers are producing the
wrong results I think is a useful first step to find out what is amiss
with this program.

(Throwing loads of -W options at it with gcc didn't show anything that
interesting.)

I next wanted to see next why lccwin32 is producing that data block (the
one output by ct_mbrotplane()) consisting of all 'A' characters, before
looking at that inconsistency issue.

And that does appear to a bug with the 64-bit version of lccwin32,
demonstrated here:

#include <stdio.h>
#include <math.h>

int main(void) {
printf("%f\n", fmod(0.445226, 1.0));
}

This produces an output of 'nan', rather than 0.445226. The program
works (in producing encrypted/decrypted output) with the 32-bit lccwin32.

I suppose what's left is seeing why that data block, regardless of
whether the encrypt/decrypt process appears to work, is why it can vary
across compilers.

Given the amount of floating point, I can't say I'm surprised, but I'd
be interesting in establishing exactly why.


Ben Bacarisse

unread,
Oct 31, 2023, 12:15:59 PM10/31/23
to
That's a very odd way of putting it. My guess is that the
program has multiple meanings (and in some cases none). The compiler is
(probably) correctly picking one of them.

> That is, the results are incorrect.

Ah, then you know more that I. What are the correct results?

> I'm not suggesting the compilers are at fault, although that is a
> possibility especially with bcc (however, see below).
>
> Probably this is not what Chris had in mind when he mentioned
> inconsistency. But finding out why those compilers are producing the wrong
> results I think is a useful first step to find out what is amiss with this
> program.

The compiler is (probably) not producing the wrong results. The program
is producing results that the author did not intend.

> (Throwing loads of -W options at it with gcc didn't show anything that
> interesting.)

I found the result of carefully chosen -W options to be interesting.
Maybe you should reconsider "throwing" options at the compiler

> And that does appear to a bug with the 64-bit version of lccwin32,
> demonstrated here:
>
> #include <stdio.h>
> #include <math.h>
>
> int main(void) {
> printf("%f\n", fmod(0.445226, 1.0));
> }
>
> This produces an output of 'nan', rather than 0.445226.

Better to say that there is a bug in the implementation. The compiler
might be implementing fmod, but it's likely to be comming from a
library. I think lccwin32 has it's own library, but it's still not
really "the compiler".

> Given the amount of floating point, I can't say I'm surprised, but I'd be
> interesting in establishing exactly why.

Yes, some of it unnecessary. For example:

unsigned long
cantor_packing(
unsigned int n0,
unsigned int n1
){
unsigned long ret = 0.5 * (n0 + n1) * (n0 + n1 + 1) + n1;

return ret;
}

There is no need for floating point arithmetic here; C's x/2 works fine
when implementing this function.

--
Ben.

bart

unread,
Oct 31, 2023, 2:35:54 PM10/31/23
to
[Another repost as i2pn2 not always sending my messges]
No spec is given. But I would say one requirement is that encrypting and
then decrypting a piece of plain text should produce the original text.

Another is that encrypted text should be secret, but lccwin32 for
example had that be the same as the plaintext! I assumed that was wrong.

There may be others to do with quality of the encryption, as well as
consistency of the encrpted data across compilers, but those two are
what stood out for me when I ran the program and which seemed obviously
wrong.


Chris M. Thomasson

unread,
Oct 31, 2023, 4:37:59 PM10/31/23
to
On 10/31/2023 4:32 AM, Ben Bacarisse wrote:
> bart <b...@freeuk.com> writes:
>
>> On 30/10/2023 23:22, bart wrote:
>>> On 30/10/2023 21:01, Chris M. Thomasson wrote:
>
>>> I tweaked the source code (used explicit assignment to fields of some
>>> structs) to be able to use my compilers.
>>> Then I tried these compilers:
>>> gcc 13.2.0 - this worked. (I assume it is supposed to show some
>>> plaintext, encrypted text starting "fog.IiQ' U'?zDjP))v$oN)?z<xT
>>> CAPNKUfB...", then the identical plaintext)
>>> tcc - failed. The encrypted text started
>>> "xy,$}lu~@NM*a%^z1YA+'N@9yrV]E...", and the decrypted was:
>>> "dEjtkuXVjq5*uzqpWXE6tkzXVjq5czuqpWXE!t9zX\j35czu30/XE!tkuX\!qocuu3pWXEjtkzXVj3oczuq4WXE!0
>>> kz.Vjqocuu3p/TEj0ku.Vj31cuz3pWXEjtkzXVj3o*uzq4W."
>>
>> Regarding tcc, a few things differ internally, but I think one clue is here:
>>
>> #define CT_MBROT_ABET_LOOKUP(mp_char) \
>> ((strchr(CT_MBROT_ABET, (mp_char))) - CT_MBROT_ABET)
>>
>> This is effectively doing the following (to get an offset into the string?):
>>
>> str("ABC", c) - "ABC";
>>
>> It is assuming that both string literals have the same address.
>
> This is an unwarranted assumption.
>
> But the result is also undefined when mp_char does not occur in the
> string which can happen for two printable ASCII characters.
>
> Chris, you should test your code more thoroughly.

Yup. This was quickly fleshed out a while back, and I recently got
reminded if it. So, I ran it again, and noticed the inconsistent
behavior between the two compilers, (MSVC and GCC). This has to be due
to undefined behavior in my code. So, yes, I agree with you, Ben. Big time.

>
>> If I move that string into a variable, then Tcc starts to work. So does
>> bcc.
>
> Saying that tcc starts to work when you fix the bug suggests that tcc
> was not working before, but it's the code that was not working. tcc
> (and presumably bcc) were working fine all along.
>
>> lccwin32 still has a problem.
>
> What's the problem? Are you sure it's lccwin32 and not the source code
> that has the problem?
>

It almost has to be errors in my code. 99.9...% ;^)

Chris M. Thomasson

unread,
Oct 31, 2023, 4:46:01 PM10/31/23
to
I can perhaps learn about some interesting output from compilers that I
have never used before? Fair enough?

Chris M. Thomasson

unread,
Oct 31, 2023, 5:05:38 PM10/31/23
to
Indeed. It ideally should work with different compilers, but the
radically infested floating point issues must be an issue. It can act
funny...

>
> Another is that encrypted text should be secret, but lccwin32 for
> example had that be the same as the plaintext! I assumed that was wrong.

Wow! That is really odd to me. Can you drill down on that some more?
Thanks bart.




> There may be others to do with quality of the encryption, as well as
> consistency of the encrpted data across compilers, but those two are
> what stood out for me when I ran the program and which seemed obviously
> wrong.

Take notice of the name... Funny fractal encryption (FFE). So, it is a
fun toy to experiment with, well, imvho that is. :^)

Chris M. Thomasson

unread,
Oct 31, 2023, 5:29:24 PM10/31/23
to
On 10/30/2023 4:52 PM, Ben Bacarisse wrote:
Fwiw, I fleshed this out back in 2015. I just got recently reminded of it.

bart

unread,
Oct 31, 2023, 6:30:07 PM10/31/23
to
That was an apparent bug in the lccwin32's implementation of fmod(),
which always returned 'nan'. It meant every byte of that data block had
the same value.

Ben Bacarisse

unread,
Oct 31, 2023, 8:39:45 PM10/31/23
to
I think we've ended up talking about different things. I've not seen
such a run. The OP posted two runs that both re-created the original
text, but which had different intermediate data.

--
Ben.

Ben Bacarisse

unread,
Oct 31, 2023, 8:44:36 PM10/31/23
to
"Chris M. Thomasson" <chris.m.t...@gmail.com> writes:

> On 10/31/2023 4:32 AM, Ben Bacarisse wrote:

>> But the result is also undefined when mp_char does not occur in the
>> string which can happen for two printable ASCII characters.
>> Chris, you should test your code more thoroughly.
>
> Yup. This was quickly fleshed out a while back, and I recently got reminded
> if it. So, I ran it again, and noticed the inconsistent behavior between the
> two compilers, (MSVC and GCC). This has to be due to undefined behavior in
> my code. So, yes, I agree with you, Ben. Big time.

I don't if you know what I'm talking about. Did you deliberately leave
out two printable ASCII characters from the alphabet?

--
Ben.

Chris M. Thomasson

unread,
Oct 31, 2023, 11:27:23 PM10/31/23
to
No.

bart

unread,
Nov 1, 2023, 6:35:40 AM11/1/23
to
Have you tried to run this program? It produces 4 lots of output:

* A big block of random text

* Some plaintext

* The encrypted text

* The decrypted text

The only results posted by the OP were /screenshots/ which showed /part/
of that first data block. One also shows a scroll-bar, but you can't
click it - it's part of the image!

So I don't know what you've seen. I've also mentioned several times that
I'm not just looking at discrepances within that data block across
compilers, but differences and errors in those 3rd and 4th parts.

bart

unread,
Nov 1, 2023, 6:59:49 AM11/1/23
to
Might be helpful to mention that they are | and ".

Ben Bacarisse

unread,
Nov 1, 2023, 7:06:10 AM11/1/23
to
You had a clue: you print the alphabet length as 93. Including space,
there are 95 "non-control" ASCII characters.

--
Ben.

David Brown

unread,
Nov 1, 2023, 8:01:31 AM11/1/23
to
| and -, as far as I could see in a quick look at the code.

It seems bizarre to spell out lists of ASCII characters in the code
rather than just a simple loop at runtime.

Ben Bacarisse

unread,
Nov 1, 2023, 9:30:11 AM11/1/23
to
bart <b...@freeuk.com> writes:

> On 01/11/2023 00:39, Ben Bacarisse wrote:
>> bart <b...@freeuk.com> writes:
>>
>
>>> No spec is given. But I would say one requirement is that encrypting and
>>> then decrypting a piece of plain text should produce the original
>>> text.
>>
>> I think we've ended up talking about different things. I've not seen
>> such a run. The OP posted two runs that both re-created the original
>> text, but which had different intermediate data.
>>
>
> Have you tried to run this program?

Yes.

> It produces 4 lots of output:
>
> * A big block of random text

I don't think it's random.

> * Some plaintext
>
> * The encrypted text
>
> * The decrypted text

And some other data. One of these is a number he calls cpack.

> The only results posted by the OP were /screenshots/ which showed /part/ of
> that first data block. One also shows a scroll-bar, but you can't click it -
> it's part of the image!

I don't follow links to images. I was going by what he posted here.
Two different run (from two different compilers) showing different value
of "cpack". This is a number that looks certain to depend on the width
of "unsigned long".

> So I don't know what you've seen.

I've seen what was posted here. I've not seen any linked images. I
don't know why people post images of text, but I don't mind because I
ignore such links anyway.

> I've also mentioned several times that I'm
> not just looking at discrepances within that data block across compilers,
> but differences and errors in those 3rd and 4th parts.

Yes, that's how I know were talking about different things.

--
Ben.

Ben Bacarisse

unread,
Nov 1, 2023, 9:44:14 AM11/1/23
to
Maybe, but the teacher in me won't go away, so I prefer point to the
problem rather than spell it out exactly.

--
Ben.

Ben Bacarisse

unread,
Nov 1, 2023, 9:52:30 AM11/1/23
to
David Brown <david...@hesbynett.no> writes:

> On 01/11/2023 11:59, bart wrote:
>> On 01/11/2023 00:44, Ben Bacarisse wrote:
>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>
>>>> On 10/31/2023 4:32 AM, Ben Bacarisse wrote:
>>>
>>>>> But the result is also undefined when mp_char does not occur in the
>>>>> string which can happen for two printable ASCII characters.
>>>>> Chris, you should test your code more thoroughly.
>>>>
>>>> Yup. This was quickly fleshed out a while back, and I recently got
>>>> reminded
>>>> if it. So, I ran it again, and noticed the inconsistent behavior between
>>>> the
>>>> two compilers, (MSVC and GCC). This has to be due to undefined behavior
>>>> in
>>>> my code. So, yes, I agree with you, Ben. Big time.
>>>
>>> I don't if you know what I'm talking about.  Did you deliberately leave
>>> out two printable ASCII characters from the alphabet?
>>>
>> Might be helpful to mention that they are | and ".
>
> | and -, as far as I could see in a quick look at the code.

No, - is there but " is not. It's a slightly more subtle bug than just
"you have missing characters" which is why I wanted Chris to look for
himself.

> It seems bizarre to spell out lists of ASCII characters in the code rather
> than just a simple loop at runtime.

Sometimes the order matters, particularly in cryptological applications.
In this case I don't think is does though.

And if the order does not matter, then even a loop is unnecessary since
the string is used only to generate indexes into it. A simple x - ' '
gives the index of x in the list of "printable" ASCII characters.

--
Ben.

David Brown

unread,
Nov 1, 2023, 3:12:45 PM11/1/23
to
On 01/11/2023 14:52, Ben Bacarisse wrote:
> David Brown <david...@hesbynett.no> writes:
>
>> On 01/11/2023 11:59, bart wrote:
>>> On 01/11/2023 00:44, Ben Bacarisse wrote:
>>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>>
>>>>> On 10/31/2023 4:32 AM, Ben Bacarisse wrote:
>>>>
>>>>>> But the result is also undefined when mp_char does not occur in the
>>>>>> string which can happen for two printable ASCII characters.
>>>>>> Chris, you should test your code more thoroughly.
>>>>>
>>>>> Yup. This was quickly fleshed out a while back, and I recently got
>>>>> reminded
>>>>> if it. So, I ran it again, and noticed the inconsistent behavior between
>>>>> the
>>>>> two compilers, (MSVC and GCC). This has to be due to undefined behavior
>>>>> in
>>>>> my code. So, yes, I agree with you, Ben. Big time.
>>>>
>>>> I don't if you know what I'm talking about.  Did you deliberately leave
>>>> out two printable ASCII characters from the alphabet?
>>>>
>>> Might be helpful to mention that they are | and ".
>>
>> | and -, as far as I could see in a quick look at the code.
>
> No, - is there but " is not.

I've looked again, and you and Bart are correct.

> It's a slightly more subtle bug than just
> "you have missing characters" which is why I wanted Chris to look for
> himself.
>
>> It seems bizarre to spell out lists of ASCII characters in the code rather
>> than just a simple loop at runtime.
>
> Sometimes the order matters, particularly in cryptological applications.

I am immediately suspicious of any cryptography that is dependent on a
character set, never mind the order of it - it sounds fragile.
Cryptography that can't deal with arbitrary data hasn't been much use
since WWII.

(Order can matter in other applications.)

> In this case I don't think is does though.
>
> And if the order does not matter, then even a loop is unnecessary since
> the string is used only to generate indexes into it. A simple x - ' '
> gives the index of x in the list of "printable" ASCII characters.
>

I didn't look much at the rest of the code. (And is it turns out, I
didn't look very hard at the character lists either!)

Chris M. Thomasson

unread,
Nov 1, 2023, 3:52:34 PM11/1/23
to
Never use this funny toy of mine, (Funny Fractal Encryption (FFE)) as a
real encryption implement, NEVER! It was for fun, not for serious work
at all. Now, I do have an experimental encryption that I think can
potentially be used. Have you seen this before?

https://groups.google.com/g/comp.lang.c/c/a53VxN8cwkY/m/XKl1-0a8DAAJ

Fwiw, here is a hyper crude write up I did:

http://funwithfractals.atspace.cc/ct_cipher

What do you think? Crap, or kind of crap?

;^)

Fwiw, here is an online version of it:

http://fractallife247.com/test/hmac_cipher/ver_0_0_0_1/

Here is a message encrypted using the default key, for all of us to see:


http://fractallife247.com/test/hmac_cipher/ver_0_0_0_1?ct_hmac_cipher=38e1fedde4d299752a59ed9d3194cbee57d335ad7f293865db2018c5594f783b087464ab88d3a9db11861ad37eb9f00a6c900a00043348ba7d6ac1d41933c6db0bd53cc0f4b8de9eb589ea745f1639c7358a3e5052c164b7268a31d075f0afb4121ec509

Chris M. Thomasson

unread,
Nov 1, 2023, 3:53:16 PM11/1/23
to
On 11/1/2023 6:29 AM, Ben Bacarisse wrote:
> bart <b...@freeuk.com> writes:
>
>> On 01/11/2023 00:39, Ben Bacarisse wrote:
>>> bart <b...@freeuk.com> writes:
>>>
>>
>>>> No spec is given. But I would say one requirement is that encrypting and
>>>> then decrypting a piece of plain text should produce the original
>>>> text.
>>>
>>> I think we've ended up talking about different things. I've not seen
>>> such a run. The OP posted two runs that both re-created the original
>>> text, but which had different intermediate data.
>>>
>>
>> Have you tried to run this program?
>
> Yes.
>
>> It produces 4 lots of output:
>>
>> * A big block of random text
>
> I don't think it's random.

It is not random at all! NOPE.

Chris M. Thomasson

unread,
Nov 1, 2023, 3:54:18 PM11/1/23
to
Thank you for the teacher in you. I think this boils down to a floating
point issue in one of my fun toys.

Ben Bacarisse

unread,
Nov 1, 2023, 4:08:50 PM11/1/23
to
"Chris M. Thomasson" <chris.m.t...@gmail.com> writes:

> On 11/1/2023 6:43 AM, Ben Bacarisse wrote:
>> bart <b...@freeuk.com> writes:
>>
>>> On 01/11/2023 00:44, Ben Bacarisse wrote:
>>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>>
>>>>> On 10/31/2023 4:32 AM, Ben Bacarisse wrote:
>>>>
>>>>>> But the result is also undefined when mp_char does not occur in the
>>>>>> string which can happen for two printable ASCII characters.
>>>>>> Chris, you should test your code more thoroughly.
>>>>>
>>>>> Yup. This was quickly fleshed out a while back, and I recently got reminded
>>>>> if it. So, I ran it again, and noticed the inconsistent behavior between the
>>>>> two compilers, (MSVC and GCC). This has to be due to undefined behavior in
>>>>> my code. So, yes, I agree with you, Ben. Big time.
>>>> I don't if you know what I'm talking about. Did you deliberately leave
>>>> out two printable ASCII characters from the alphabet?
>>>
>>> Might be helpful to mention that they are | and ".
>> Maybe, but the teacher in me won't go away, so I prefer point to the
>> problem rather than spell it out exactly.
>
> Thank you for the teacher in you. I think this boils down to a floating
> point issue in one of my fun toys.

What is "this"? The "this" I am talking about has nothing to do with
floating point arithmetic. It's a simple matter of forgetting about |
and " when you drew up the alphabet.

--
Ben.

Chris M. Thomasson

unread,
Nov 1, 2023, 4:12:20 PM11/1/23
to
On 11/1/2023 1:08 PM, Ben Bacarisse wrote:
> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>
>> On 11/1/2023 6:43 AM, Ben Bacarisse wrote:
>>> bart <b...@freeuk.com> writes:
>>>
>>>> On 01/11/2023 00:44, Ben Bacarisse wrote:
>>>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>>>
>>>>>> On 10/31/2023 4:32 AM, Ben Bacarisse wrote:
>>>>>
>>>>>>> But the result is also undefined when mp_char does not occur in the
>>>>>>> string which can happen for two printable ASCII characters.
>>>>>>> Chris, you should test your code more thoroughly.
>>>>>>
>>>>>> Yup. This was quickly fleshed out a while back, and I recently got reminded
>>>>>> if it. So, I ran it again, and noticed the inconsistent behavior between the
>>>>>> two compilers, (MSVC and GCC). This has to be due to undefined behavior in
>>>>>> my code. So, yes, I agree with you, Ben. Big time.
>>>>> I don't if you know what I'm talking about. Did you deliberately leave
>>>>> out two printable ASCII characters from the alphabet?
>>>>
>>>> Might be helpful to mention that they are | and ".
>>> Maybe, but the teacher in me won't go away, so I prefer point to the
>>> problem rather than spell it out exactly.
>>
>> Thank you for the teacher in you. I think this boils down to a floating
>> point issue in one of my fun toys.
>
> What is "this"? The "this" I am talking about has nothing to do with
> floating point arithmetic. It's a simple matter of forgetting about |
> and " when you drew up the alphabet.
>

I am still wondering why I get two different cpack outputs using
different compilers (GCC vs. MSVC) with the code as is.

756768

vs:

95375807

Almost has to be a floating point issue? Or some undefined behavior I
overlooked?

Richard Harnden

unread,
Nov 1, 2023, 4:32:39 PM11/1/23
to
On 30/10/2023 21:01, Chris M. Thomasson wrote:
> This has to be undefined behavior. Check it out:
>
> Here is my C code for a fun toy experimental fractal:
>
> https://pastebin.com/raw/fcV5YiJH
> (raw link to text...)
>

Here's some clang weirdness ...

$ gcc --version
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.0.0
Thread model: posix
InstalledDir:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

and:

$ gcc -std=c99 -pedantic -W -Wall -fsanitize=undefined -O2 -lm ffe.c
ffe.c:305:18: warning: taking the absolute value of unsigned type
'unsigned int' has no effect [-Wabsolute-value]
ec = abs(icount - ec);
^
ffe.c:305:18: note: remove the call to 'abs' since unsigned values
cannot be negative
ec = abs(icount - ec);
^~~
1 warning generated.

If you follow that advise, then it doesn't decrypt.

In fact, it doesn't decrypt in differennt ways depending on -On used.

(gcc proper doesn't complain about the abs)


Ben Bacarisse

unread,
Nov 1, 2023, 5:12:54 PM11/1/23
to
So talk about that in the sub-thread that is about exactly that topic.
If you post a reply to a message about missing characters -- even if the
wider thread also included talk of other things -- you should be talking
about missing characters.

And, especially, if you use words like "this" and "it" they should
relate to the immediate topic, not something else in previous posts or
other parts of the thread.

> 756768
>
> vs:
>
> 95375807
>
> Almost has to be a floating point issue? Or some undefined behavior I
> overlooked?

Well, in a post in reply to Bart, I gave some information about that so
now I'm going to mess up this sub thread by going back to it...

The code that calculates cpack mixes unsigned int and unsigned long int
arithmetic. On Windows, unsigned long int is 32 bits, but it's usually
64 bits on Linux. There seems to be no logic behind this mixing, but
you won't get the same result with different sized integer types.

The situation is made worse by using floating point to halve an integer
quantity (in cantor_packing). In effect, that introduces a 52-bit
integer type into the mix as well.

To cap it all, CT_FFE_ABET_LOOKUP is of type ptrdiff_t -- a /signed/
integer type whose size can vary between systems.

It would be almost impossible to state, mathematically, what cpack's
value "should" be. The value is derived from a chaotic mix of wrapping
between 32 and sometimes 64 bit values as well as rounding to 52 bits of
accuracy.

Even the simple cantor_packing function relies on wrapping and/or
rounding to give a result that is not mathematically correct.

Since you rely on unsigned arithmetic being modular, the only way you'll
get the same result for cpack on all systems is to specify exactly what
arithmetic you want. The crude way is to use integer types with
specified sizes, avoid signed integer types and replace "0.5*..." with
with ".../2".

--
Ben.

Chris M. Thomasson

unread,
Nov 1, 2023, 5:17:18 PM11/1/23
to
Agreed. However, that would take the funny part out of it...

;^)

Chris M. Thomasson

unread,
Nov 1, 2023, 5:30:29 PM11/1/23
to
Fwiw, here is an fun online version of it:

http://funwithfractals.atspace.cc/ffe

0.3890382556464768 0.4591590239305639
0.2729659079628294 0.2743403616928193

D2 6D 58 D4 6B C8 7D 7E CA B3 68 34 2C A6 23 AB 2F B5 8F 3F 6B 24

Copy and replace the contents of the ciphertext box with the copied
ciphertext in this message, click decrypt. It should work, the funny
part is if it cannot work between certain browsers! lol.

Fwiw, here is a screen shot of what I get:

https://i.ibb.co/jWnb7hp/image.png

Ben Bacarisse

unread,
Nov 1, 2023, 5:36:47 PM11/1/23
to
That's "compiler" advice! While icount - ec is indeed unsigned, the
conversion to int (the argument type of abs) is sometimes undefined due
to overflow. So removing the call is fine in the eyes of a compiler
because the result will be the same in the defined cases and compilers
don't care about the undefined ones.

Apparently, the code relies on the undefined conversion.

> In fact, it doesn't decrypt in differennt ways depending on -On used.
>
> (gcc proper doesn't complain about the abs)

With lots of warnings turned on I get:

321 | ec = abs(icount - ec);
| ^
cmt.c:321:18: warning: taking the absolute value of unsigned type ‘unsigned int’ has no effect [-Wabsolute-value]
321 | ec = abs(icount - ec);
| ^~~
cmt.c:321:29: warning: conversion to ‘int’ from ‘unsigned int’ may change the sign of the result [-Wsign-conversion]
321 | ec = abs(icount - ec);
| ~~~~~~~^~~~

I would have loved to have this level of warning when I was first using
C all those years ago. And as for valgrind and -fsanitize=undefined, I
could only dream of such things.

--
Ben.

Ben Bacarisse

unread,
Nov 1, 2023, 5:44:06 PM11/1/23
to
Ah, sorry. I thought you wanted to fix the code. I'll stick to
answering your questions literally!

>>> Almost has to be a floating point issue?

No, not here.

>>> Or some undefined behavior I overlooked?

No, not here, though there is plenty of undefined behaviour elsewhere.

--
Ben.

Richard Harnden

unread,
Nov 1, 2023, 5:55:02 PM11/1/23
to
-fsanitize=undefined has shown some of my 100% perfect programs to, in
fact, be 99% fluke.



bart

unread,
Nov 1, 2023, 6:59:53 PM11/1/23
to
I had trouble getting four compilers to give different cpack values,
although they sometimes diverged later especially using float rather
than double.

I did see a consistent difference on cpack with lccwin32 (32-bits)
though. (Note that at this point I am using u64 not 'unsigned long'.)

Tracing it through, the culprit is likely to be the cantor_packing
function. If I extract into this test program:


#include <stdio.h>

typedef unsigned long long u64;

u64 cantor_packing(unsigned int n0, unsigned int n1) {
u64 ret = 0.5 * (n0 + n1) * (n0 + n1 + 1) + n1;

printf("%f\n", (double)(n0+n1));
printf("%f\n", 0.5*(n0+n1));
printf("%f\n", 0.5*(n0+n1)*(n0+n1+1));
printf("%f\n", 0.5*(n0+n1)*(n0+n1+1)+n1);

return ret;
}

int main(void) {
u64 a;

a=cantor_packing(3557082894, 3037);
printf("%llu", a);
}


Then, ignoring those first printfs for now, all 4 compilers give the
same final result execpt lccwin32. But with those printfs in place,
there is some divergence:


c:\c>mcc d.c && d
Compiling d.c to d.exe
3557085931.000000
1778542965.500000
6326430162037611500.000000
6326430162037614600.000000
6326430162037614592

c:\c>tcc d.c && d
3557085931.000000
1778542965.500000
6326430162037611500.000000
6326430162037614600.000000
6326430162037614592

c:\c>gcc d.c && a
3557085931.000000
1778542965.500000
6326430162037611520.000000
6326430162037614592.000000
6326430162037614592

c:\c>\lcc\bin\lc d.c && d
3557085931.000000
1778542965.500000
6326430162037611500.000000
6326430162037614600.000000
6326430162037614383

Based on the last value, 1,2,3 give the same result and 4 is different.
Based on those intermediates, 1,2 and 4 are the same, and 3 is different.

So the interaction between the 0.5 (which presumably is 'double'), and
those u32 values and u64 result causes problems.

I don't know whether f64*u32*u32 does f64*u32 first or u32*u32. But I
think that either way, the 52-bit integer accuracy of f64 may be
breached at some point.

The funny thing is, the exact result of tha expression inside
cantor_packing using the given values is:

6326430162037614383

(About 1000 times bigger than 52 bits). Only lccwin32 gets it exactly
right, all the others get it wrong!

If I change the function to avoid floating point:

#include <stdio.h>

typedef unsigned long long u64;

u64 cantor_packing(unsigned int n0, unsigned int n1) {
u64 ret = (n0 + n1) * (n0 + n1 + 1)/2 + n1;
return ret;
}

int main(void) {
u64 a;

a=cantor_packing(3557082894, 3037);
printf("%llu", a);
}

Then the behaviour is more consistent:

c:\c>mcc d.c && d
Compiling d.c to d.exe
680634159

c:\c>tcc d.c && d
680634159

c:\c>gcc d.c && a
680634159

c:\c>\lcc\bin\lc d.c && d
680634159

However the result is 'wrong' as evaluation is done as u32 not u64.
Changing the parameters to u64 (why does anyone still bother with 32
bits?) yields the above result of 6326430162037614383 in all four cases.

Chris M. Thomasson

unread,
Nov 1, 2023, 7:03:09 PM11/1/23
to
I might have some time tonight to work on it again.

David Brown

unread,
Nov 2, 2023, 5:05:01 AM11/2/23
to
On 01/11/2023 20:52, Chris M. Thomasson wrote:
> On 11/1/2023 12:12 PM, David Brown wrote:

>> I am immediately suspicious of any cryptography that is dependent on a
>> character set, never mind the order of it - it sounds fragile.
>> Cryptography that can't deal with arbitrary data hasn't been much use
>> since WWII.
>
> Never use this funny toy of mine, (Funny Fractal Encryption (FFE)) as a
> real encryption implement, NEVER! It was for fun, not for serious work
> at all. Now, I do have an experimental encryption that I think can
> potentially be used. Have you seen this before?
>
> https://groups.google.com/g/comp.lang.c/c/a53VxN8cwkY/m/XKl1-0a8DAAJ
>
> Fwiw, here is a hyper crude write up I did:
>
> http://funwithfractals.atspace.cc/ct_cipher
>
> What do you think? Crap, or kind of crap?
>
> ;^)
>

I am not a cryptography expert, but I am leaning towards the first
choice :-) I realise it is "pre-alpha version 0.0.0", and more playing
with ideas than serious encryption. But I can give you a couple of
points and suggestions, which might be of use to you.

First, cryptography is mathematics. It makes things clearer if your
algorithms are written mathematically. The algorithms are not code -
they are maths, and good typography and good naming in maths is
different from good layout and good naming in programming. And clear
expressions are much better than descriptions in text.

So don't write
Set I_P is used as an index for P, set it to zero.

Prefer
iₚ ← 0

(Use the best layout tools you are familiar with - raw html, LaTeX,
LibreOffice's formula editors, whatever.)

Don't think in C - think in mathematics. So don't invent arrays and
variables and change them, but write expressions and name them - then
leave them unchanged. Rather than "Prepend R to P", write "Pʹ ← R ++ P"
and introduce a new name. It is /hugely/ easier to comprehend the
algorithm, and prove its correctness and other features, when you do this.


Then there are some basic cryptography rules. Your main hash algorithm
has a certain size of output, such as 32-byte (for SHA-256). There is
then no point in using a key that has more than 256 bits of entropy, nor
is there any point in using random salt with more entropy than that -
you are simply guaranteeing duplications. If the key is expected to be
plain text that people can remember, then it needs to be much longer to
get 256 bits of entropy (you use a long low-entropy text, then run it
though a secure hash to get a condensed key with high relative entropy).


As far as I can tell, the guts of your idea is that you are doing a
sliding xor encryption but changing that encryption key as you go along,
based on feeding the message into a hash function. It's an interesting
idea, but I don't think it is actually a good thing - I suspect it
actually decreases the effectiveness of the encryption, and my gut
feeling is that carefully crafted plain texts can be used as an attack
to get the encryption key out. But you'd be better asking a real
cryptologist about that.


Don't let that stop you playing around with these, however - there's
always fun to be had with this kind of thing.



David Brown

unread,
Nov 2, 2023, 5:10:28 AM11/2/23
to
On 31/10/2023 00:52, Ben Bacarisse wrote:
> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>
>> This has to be undefined behavior. Check it out:
>>
>> Here is my C code for a fun toy experimental fractal:
>>
>> https://pastebin.com/raw/fcV5YiJH
>> (raw link to text...)
>
> Ask your compiler for the maximum number of warnings and you should see
> lots. For some reason you are mixing types in a peculiar way, and since
> some of those types often have different sizes you will get different
> arithmetic results on different systems.
>
>> The cpack is different on the two different compilers. Oh, that is always
>> fun!
>
> You need to decide what integer types you really want.
>

And the sane way to do that is to stick strictly to <stdint.h> types, so
that the sizes are independent of the compiler and platform.


Ben Bacarisse

unread,
Nov 2, 2023, 5:52:49 AM11/2/23
to
Hmm... I would not want to say that exactly. Firstly, it perpetuates
the misconception that stdint.h only defines the exact-width types
helping the world to forget about the [u]int_(least|fast)N_t types!
Secondly, lots of algorithms can be written perfectly well using C's
ordinary types. The key is to know what the type names mean.

--
Ben.

bart

unread,
Nov 2, 2023, 7:32:10 AM11/2/23
to
On 02/11/2023 09:52, Ben Bacarisse wrote:
> David Brown <david...@hesbynett.no> writes:
>
>> On 31/10/2023 00:52, Ben Bacarisse wrote:
>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>
>>>> This has to be undefined behavior. Check it out:
>>>>
>>>> Here is my C code for a fun toy experimental fractal:
>>>>
>>>> https://pastebin.com/raw/fcV5YiJH
>>>> (raw link to text...)
>>> Ask your compiler for the maximum number of warnings and you should see
>>> lots. For some reason you are mixing types in a peculiar way, and since
>>> some of those types often have different sizes you will get different
>>> arithmetic results on different systems.
>>>
>>>> The cpack is different on the two different compilers. Oh, that is always
>>>> fun!
>>> You need to decide what integer types you really want.
>>
>> And the sane way to do that is to stick strictly to <stdint.h> types, so
>> that the sizes are independent of the compiler and platform.
>
> Hmm... I would not want to say that exactly. Firstly, it perpetuates
> the misconception that stdint.h only defines the exact-width types
> helping the world to forget about the [u]int_(least|fast)N_t types!

Is that a bad thing?

I mean, which other current languages, other than C++, that have
size-specific integer types, also have a set of 'least' and 'fast' versions?

It doesn't seem to something that the creators of other languages lose
sleep over.

Those types appear to be relevant only to unusual architectures that
only C bothers with.

> Secondly, lots of algorithms can be written perfectly well using C's
> ordinary types. The key is to know what the type names mean.

Not this one. 'int' might be 16 bits or 32 bits or 64 or anything above
16, but is likely to be 32 bits or typical platforms.

'long' might be 32 bits or more, and /is/ commonly either 32 bits or 64
bits even on Linux.




David Brown

unread,
Nov 2, 2023, 8:34:55 AM11/2/23
to
On 02/11/2023 10:52, Ben Bacarisse wrote:
> David Brown <david...@hesbynett.no> writes:
>
>> On 31/10/2023 00:52, Ben Bacarisse wrote:
>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>
>>>> This has to be undefined behavior. Check it out:
>>>>
>>>> Here is my C code for a fun toy experimental fractal:
>>>>
>>>> https://pastebin.com/raw/fcV5YiJH
>>>> (raw link to text...)
>>> Ask your compiler for the maximum number of warnings and you should see
>>> lots. For some reason you are mixing types in a peculiar way, and since
>>> some of those types often have different sizes you will get different
>>> arithmetic results on different systems.
>>>
>>>> The cpack is different on the two different compilers. Oh, that is always
>>>> fun!
>>> You need to decide what integer types you really want.
>>
>> And the sane way to do that is to stick strictly to <stdint.h> types, so
>> that the sizes are independent of the compiler and platform.
>
> Hmm... I would not want to say that exactly. Firstly, it perpetuates
> the misconception that stdint.h only defines the exact-width types
> helping the world to forget about the [u]int_(least|fast)N_t types!

These could well have some use for code such as this (without having
studied the code in detail). Sometimes it makes sense to use the "fast"
types for intermediary calculations - on x86-64 (at least on Linux), for
example, the "int_fast32_t" type is 64 bit and can give noticeably more
efficient code than "int32_t" or "int".

So I would not want to dismiss the "fast" types even though I think the
main point here is to use the unsigned size-specific types to get the
desired modulo effects in a platform-independent way.

(The "least" types are, I think, less useful for most code - they are
only needed if you are targeting systems that might not have 8-bit or
other power-of-two sized types, and even then they are only needed for
arrays or larger storages.)

> Secondly, lots of algorithms can be written perfectly well using C's
> ordinary types. The key is to know what the type names mean.
>

You can always get by without the explicitly sized types. But you'll
typically either need to use explicit masks (like using "unsigned long"
and masking with 0xffffffff to get the 32-bit modulo effects you want),
or you'll end up duplicating the <stdint.h> exact size types using
<limits.h>, conditional compilation and typedefs. Your results will not
be more portable (since any C compiler that supports "long long" will at
least partially support C99, and it will have <stdint.h>). The code
will not be simpler or clearer, but will be inevitably be messier, and
have a greater risk of errors (as seen in Chris' code). And the code
will not be more efficient, but could easily be less efficient - you can
manually create the fixed-size types, assuming the platform supports
them, but you can't create the "fast" types.

Of course you can do a lot of coding with the standard integer types,
and of course knowing what the types mean is vital to this, especially
for portable code. But sometimes the <stdint.h> types are simply much
better for the task in hand.


David Brown

unread,
Nov 2, 2023, 8:53:20 AM11/2/23
to
Like x86-64 ?

I don't see any use of the "least" types, except on unusual
architectures that don't support all of the common 8-bit, 16-bit, 32-bit
and 64-bit types. It's a good thing that C supports these
architectures, because while some of these are outdated and of
historical interest only, others are valid, active and popular within
their niche markets. It is understandable that most languages don't
support them, but good that C does.

The "fast" types are more useful. They can be very helpful when making
code that works well across different target sizes, as is very common in
libraries for embedded development, reducing or avoiding the mess of
"port" includes and library-specific type names. And on bigger systems,
such as normal PC's, they give you more efficient code while saying
explicitly what you are looking for in the type.

So on x86-64 for Linux, "int_fast16_t" and "int_fast32_t" are both
64-bit. On x86-64 for Windows, since Windows always likes to be
different from everyone else, "int_fast16_t" and "int_fast32_t" are both
32-bit. "int8_t" is 8-bit on both systems.

bart

unread,
Nov 2, 2023, 10:08:00 AM11/2/23
to
So what were the reasons for Linux to use 64 bits for int_fast16_t and
Windows to use 32 bits?

If I wanted an array of 100M int_fast16_t types, I would guess that an
actual 16-bit type is faster than either 32 or 64 bits because it uses a
lot less memory.

But for individual calculations, both 16-bit and 64-bit instructions
frequently need an extra prefix byte over 32 bits. This is not
necessarily faster, but overall there will be less code.

So for both these cases, Windows' 32 bits make more sense than 64.

(If I look at the actual stdint.h for mingw, int16_t is just 'short'. On
my WSL, inside /usr/include/stdint.h, it is defined on top of long,
which may be 32 or 64 bits.)

David Brown

unread,
Nov 2, 2023, 11:54:01 AM11/2/23
to
I am not privy to the decision-making processes. But I expect Linux
x86-64 (and almost every other 64-bit compiler I checked on godbolt,
apart from Windows) does this because using 64-bit registers is faster
in at least some cases. Typically it helps avoid things like sign or
zero extension when loading a register, and can probably simplify some
instruction formats (depending on the target). I believe pointer +
offset calculations are more efficient with native size for the offset.

MS probably aimed for consistency with their 32-bit ABI, rather than
making better use of 64-bit facilities, just as they did with "long". I
wonder if they are regretting that decision these days?

Both Linux and Windows use 32-bit for "int_fast16_t" in 32-bit targets.
And all use 8-bit for "int_fast8_t", as far as I saw - I suppose most
8-bit values get promoted to "int" before most use-cases anyway.

> If I wanted an array of 100M int_fast16_t types, I would guess that an
> actual 16-bit type is faster than either 32 or 64 bits because it uses a
> lot less memory.

Yes. int_fast16_t is the wrong type to use for an array. The "fast"
types make sense for local variables and perhaps some solitary
statically allocated data. They are fast in registers, not in memory.
For arrays (other than tiny ones), cache effects mean that small is
fast, and thus "int_least16_t" is going to be the fastest type
supporting 16-bit values. (And as noted previously, this will be the
same as int16_t on all but specialised targets.)

>
> But for individual calculations, both 16-bit and 64-bit instructions
> frequently need an extra prefix byte over 32 bits. This is not
> necessarily faster, but overall there will be less code.
>

On x86-64, these prefixes usually get swallowed so early in the
instruction decode that they make no difference to the speed, unless you
get enough of them for the extra cache load to be relevant.

> So for both these cases, Windows' 32 bits make more sense than 64.
>

People who know far more about this than me, and even more than you (I
know you are more familiar with the details of x86-64 instructions than
I am), and who care about efficiency more than Microsoft (for whom
consistency with old flaws is more important than efficiency of new
systems), picked 8-byte types for the "fast" types on 64-bit systems. I
am confident that they did so on more evidence and technical data than
we have here.

Of course there will be situations when 32-bit types will be faster than
64-bit types - such decisions are based on statistical information and
common patterns, and will never be perfect in all circumstances.

> (If I look at the actual stdint.h for mingw, int16_t is just 'short'. On
> my WSL, inside /usr/include/stdint.h, it is defined on top of long,
> which may be 32 or 64 bits.)
>

"int16_t" must be exactly 16 bits, and many <stdint.h> files will define
it based on "short int". It will not be based on "long", unless using
some unusual compiler extensions. (In the AVR port of gcc, the usual
<stdint.h> defines all the types as typedefs of "int" with gcc
attributes to control the size. I don't know why it does that, and I
haven't seen it elsewhere.)


Chris M. Thomasson

unread,
Nov 2, 2023, 1:51:58 PM11/2/23
to
Thank you David. Crap is as it is... Simply because its never been
properly examined by professionals! Sigh... Btw, did you find some time
to run my example Python program? Btw, thanks for all of your advise on
how to improve my hyper crude little write up. Thanks man. Fwiw, here is
my little python experimental implementation of ver:0.0.0 (Pre-Alpha)

_____________________________
# Chris M. Thomasson Copyright 2018 (c)
# Experimental HMAC Cipher
#____________________________________________________________


# Our external libs
#____________________________________________________________
import random;
import hashlib;
import hmac;


# Some Utilities
#____________________________________________________________
def ct_bytes_to_hex(origin, offset):
hex = "";
n = len(origin);
t = "0123456789ABCDEF";
for i in range(offset, n):
c = ord(origin[i]);
nibl = c & 0x0F;
nibh = (c & 0xF0) >> 4;
hex = hex + t[nibh];
hex = hex + t[nibl];
hex = hex + " ";
if (not ((i + 1) % 16) and i != n - 1):
hex = hex + "\r\n";
return hex;


# Generate n random bytes
# These need should ideally be from a truly random, non-repeatable
# source. TRNG!
def ct_rand_bytes(n):
rb = "";
for i in range(n):
rb = rb + chr(random.randint(0, 255));
return rb;


# The Secret Key
# Contains all the parts of the secret key
#____________________________________________________________
class ct_secret_key:
def __init__(self, hmac_key, hash_algo, rand_n):
self.hmac_key = hmac_key;
self.hash_algo = hash_algo;
self.rand_n = rand_n;

def __repr__(self):
return "hmac_key:%s\nhash_algo:%s\nrand_n:%s" %
(ct_bytes_to_hex(self.hmac_key, 0), self.hash_algo, self.rand_n);

def __str__(self): return self.__repr__();


# The Ciphertext or Plaintext
# It holds the bytes of a ciphertext or a plaintext
#____________________________________________________________
class ct_bin:
def __init__(self, ctxt):
self.bytes = ctxt;
def __repr__(self):
return "%s" % (ct_bytes_to_hex(self.bytes, 0));

def __str__(self): return self.__repr__();


# The Crypt Round Function
#____________________________________________________________
def ct_crypt_round(SK, P, M):
H = hmac.new(SK.hmac_key.encode(), None, SK.hash_algo);
H.update(SK.hmac_key[::-1].encode());
C = "";
I_P = 0;
I_P_N = len(P.bytes);
while (I_P < I_P_N):
D = H.digest();
I_D = 0;
I_D_N = len(D);
while (I_P < I_P_N and I_D < I_D_N):
C_I_P = ord(P.bytes[I_P]) ^ D[I_D];
C = C + chr(C_I_P);
if (M == False):
H.update(P.bytes[I_P].encode());
H.update(chr(C_I_P).encode());
else:
H.update(chr(C_I_P).encode());
H.update(P.bytes[I_P].encode());
I_P = I_P + 1;
I_D = I_D + 1;
return ct_bin(C);


# The Crypt Function
#____________________________________________________________
def ct_crypt(SK, P, M):
if (M == False):
R = ct_rand_bytes(SK.rand_n);
P.bytes = R + P.bytes;
C = ct_crypt_round(SK, P, M);
C_1 = ct_bin(C.bytes[::-1]);
C = ct_crypt_round(SK, C_1, M);
if (M == True):
size = len(C.bytes) - SK.rand_n;
C.bytes = C.bytes[SK.rand_n : SK.rand_n + size];
return C;


# The Main Program
#____________________________________________________________

# Alice and Bob's Secret Key
#____________________
SK = ct_secret_key(
"This is the HMAC Key. It should be a crypto secure key! Damn it.",
hashlib.sha384, # The hash function. It should be a crypto secure hash.
73 # The number of bytes. The should be generated by a TRNG
);
print("%s" % (SK));

# Alice's Plaintext
#____________________
Original_Plaintext =
"ABCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDE";
A_P = ct_bin(Original_Plaintext);
print(
"\n\nAlice's Plaintext Bytes:"
"\n____________________\n%s\n" % (A_P)
);

# Encrypt
#____________________
C = ct_crypt(SK, A_P, False);
print(
"\n\nCiphertext Bytes:"
"\n____________________\n%s\n" % (C)
);

# Decrypt
#____________________
B_P = ct_crypt(SK, C, True);
print(
"\n\nBob's Ciphertext Bytes:"
"\n____________________\n%s\n" % (B_P)
);


if (B_P.bytes != Original_Plaintext):
print("DATA CORRUPTED!");
_____________________________


Btw, David, when you get some free time, can you critique my python
here? Thanks.

:^)

Chris M. Thomasson

unread,
Nov 2, 2023, 2:03:13 PM11/2/23
to
[...]
> Btw, David, when you get some free time, can you critique my python
> here? Thanks.

Oops! Sorry for that dumb ass comment! Why would you critique my python
code and post it here. Sorry! ;^o

>
> :^)

David Brown

unread,
Nov 2, 2023, 3:02:35 PM11/2/23
to
I can't promise I'll get time to try any of the code (C or Python), or
critique them. But I hope my comments on the algorithm and how to
describe it are helpful to you.


Chris M. Thomasson

unread,
Nov 2, 2023, 3:03:51 PM11/2/23
to
Very helpful. Thanks again, David. :^)

bart

unread,
Nov 2, 2023, 3:16:17 PM11/2/23
to

On 02/11/2023 15:53, David Brown wrote:
> On 02/11/2023 15:07, bart wrote:

>> So what were the reasons for Linux to use 64 bits for int_fast16_t
and Windows to use 32 bits?
>>

>> So for both these cases, Windows' 32 bits make more sense than 64.
>>
>
> People who know far more about this than me, and even more than you
(I know you are more familiar with the details of x86-64 instructions
than I am), and who care about efficiency more than Microsoft (for whom
consistency with old flaws is more important than efficiency of new
systems), picked 8-byte types for the "fast" types on 64-bit systems. I
am confident that they did so on more evidence and technical data than
we have here.

This is in line with my idea that using a 64-bit 'int' in C would have
been better, as discussed earlier in the year. As it is, 'int' is
usually 32 bits, and is still used extensively in programs rather than
explicitly requesting a 64-bit type.

It would eliminate a lot of problems, and perhaps fixed some of the
issues in the OP's program.

>
> Of course there will be situations when 32-bit types will be faster
than 64-bit types - such decisions are based on statistical information
and common patterns, and will never be perfect in all circumstances.
>
>> (If I look at the actual stdint.h for mingw, int16_t is just
'short'. On my WSL, inside /usr/include/stdint.h, it is defined on top
of long, which may be 32 or 64 bits.)
>>
>
> "int16_t" must be exactly 16 bits, and many <stdint.h> files will
define it based on "short int". It will not be based on "long", unless
using some unusual compiler extensions. (In the AVR port of gcc, the
usual <stdint.h> defines all the types as typedefs of "int" with gcc
attributes to control the size. I don't know why it does that, and I
haven't seen it elsewhere.)

Sorry, I meant 'int_fast16_t' was defined as 'short' on mingw and 'long'
on WSL.


Ben Bacarisse

unread,
Nov 2, 2023, 4:29:04 PM11/2/23
to
"Chris M. Thomasson" <chris.m.t...@gmail.com> writes:

> On 11/2/2023 2:04 AM, David Brown wrote:
>> First, cryptography is mathematics.  It makes things clearer if your
>> algorithms are written mathematically.
...
>> Don't let that stop you playing around with these, however - there's
>> always fun to be had with this kind of thing.
>
> Thank you David. Crap is as it is... Simply because its never been properly
> examined by professionals! Sigh...

There's a chicken-and-egg situation here. No professional will examine
it while it's "crap" so if it's crap through lack of review it will
remain so. In fact, no professional cryptographer will review it when
the fundamental algorithm is unspecified. To be taken seriously you
need to specify the method, as David says, mathematically. (I think you
had a go once in sci.crypt though that might have been for a different
algorithm.)

Anyway, also as David says, you can still have fun.

--
Ben.

Ben Bacarisse

unread,
Nov 2, 2023, 4:43:38 PM11/2/23
to
bart <b...@freeuk.com> writes:

> On 02/11/2023 09:52, Ben Bacarisse wrote:
>> David Brown <david...@hesbynett.no> writes:
>>
>>> On 31/10/2023 00:52, Ben Bacarisse wrote:
>>>> "Chris M. Thomasson" <chris.m.t...@gmail.com> writes:
>>>>
>>>>> This has to be undefined behavior. Check it out:
>>>>>
>>>>> Here is my C code for a fun toy experimental fractal:
>>>>>
>>>>> https://pastebin.com/raw/fcV5YiJH
>>>>> (raw link to text...)
>>>> Ask your compiler for the maximum number of warnings and you should see
>>>> lots. For some reason you are mixing types in a peculiar way, and since
>>>> some of those types often have different sizes you will get different
>>>> arithmetic results on different systems.
>>>>
>>>>> The cpack is different on the two different compilers. Oh, that is always
>>>>> fun!
>>>> You need to decide what integer types you really want.
>>>
>>> And the sane way to do that is to stick strictly to <stdint.h> types, so
>>> that the sizes are independent of the compiler and platform.
>> Hmm... I would not want to say that exactly. Firstly, it perpetuates
>> the misconception that stdint.h only defines the exact-width types
>> helping the world to forget about the [u]int_(least|fast)N_t types!
>
> Is that a bad thing?

Yes.

> I mean, which other current languages, other than C++, that have
> size-specific integer types, also have a set of 'least' and 'fast'
> versions?
>
> It doesn't seem to [be] something that the creators of other languages
> lose sleep over.

They don't seem to, no. I wonder if the fact that C remains one of the
most widely used programming languages is in any way related to that.

> Those types appear to be relevant only to unusual architectures that only C
> bothers with.
>
>> Secondly, lots of algorithms can be written perfectly well using C's
>> ordinary types. The key is to know what the type names mean.
>
> Not this one.

I am 100% sure that you don't know that to be the case. Why? Because I
am 100% sure that not even Chris knows what the actual algorithm is.
You may be right, and if anyone ever specifies the algorithm we may even
be able to determine the facts of the matter, but we can't do so now.

--
Ben.

Chris M. Thomasson

unread,
Nov 2, 2023, 4:47:43 PM11/2/23
to
Basically, my Funny Fractal Encryption is based on Julia sets. I was
just poking around having fun wrt trying to use an escape time version
as a form of encryption. So, there is no set algorithm. You are
basically right.


http://funwithfractals.atspace.cc/ffe/

0.23046159622517684 0.3470667287528152
0.25771116242735903 0.10157512574580697

45 2F 4D 81 0F 38 05 2A 4C 8D A2 CB E8 4C 07 99 2A 82 CD CB 36 E6 E3 16
7C 69 87 C3 81 2B E3 B6 76 C5 5B 7D F4 8E D0 23 8D 68 3E B4 49 FD FB 00
95 2A 92 3F 48 F3 5C 36 F9 38 9D 72 4E 1E 06 32 0D 93 27 36 5A A0 C9 64
86 71 DA CA 78 E3 02 71 B7 D0 39 18 77 59 E1 E1 EF 6D F1 4E AA 8C CE EE
AC A0 CB 34 77 94 20 F6 0C 18 C5 A0 CF FE 1C E0 49 1E C8 92 6F B2 B3 42
20 AD 7F 40 27 84 0C 40 80 75 D2 68 6E B7 89 3C D7 7C 7C D8 6C 84 3E 6C
4D A3 0B 74 18 FC CE 09 91 54 86 F8 21 F9 00 68 B1 B7 67 29 4E 4A CD 16
CF 1E 74 0E EF 79 FD 07 83 E1 93 0E 97 19 B6 64 85 C2 98 52 3D FA 71 DF
61 DA 4E 7E 43 B0 17 E8 A1 07 9A 04 2E C5 B4 87 36 63 68 FE BC 35 82 77
F5 30 B1 4C

David Brown

unread,
Nov 3, 2023, 5:24:10 AM11/3/23
to
And it's also worth remembering that not all encryption needs to be
"professional" to be useful. Sometimes a quick and simple scheme is
good enough. There's plenty of scope for ideas that give some basic
encryption with implementations that are very efficient on some level of
hardware (whether it be tuned to the latest x86-64 SIMD units or to
small microcontrollers).

(Not that Chris' current scheme is quick or simple!)


David Brown

unread,
Nov 3, 2023, 5:34:15 AM11/3/23
to
On 02/11/2023 20:15, bart wrote:
>
> On 02/11/2023 15:53, David Brown wrote:
> > On 02/11/2023 15:07, bart wrote:
>
> >> So what were the reasons for Linux to use 64 bits for int_fast16_t
> and Windows to use 32 bits?
> >>
>
> >> So for both these cases, Windows' 32 bits make more sense than 64.
> >>
> >
> > People who know far more about this than me, and even more than you
> (I know you are more familiar with the details of x86-64 instructions
> than I am), and who care about efficiency more than Microsoft (for whom
> consistency with old flaws is more important than efficiency of new
> systems), picked 8-byte types for the "fast" types on 64-bit systems.  I
> am confident that they did so on more evidence and technical data than
> we have here.
>
> This is in line with my idea that using a 64-bit 'int' in C would have
> been better, as discussed earlier in the year. As it is, 'int' is
> usually 32 bits, and is still used extensively in programs rather than
> explicitly requesting a 64-bit type.
>

Yes. I think you have some good arguments for 64-bit "int". I think,
however, the need for 8-bit, 16-bit, 32-bit and 64-bit sizes effectively
rules that out for C - it seems no one wants to add extended integer
types to make this work. (I once saw an April Fool's proposal to add
"long short int", "short long int", and endless combinations to C in
order to generate types of any sizes. But I can't find it at the moment.)

> It would eliminate a lot of problems, and perhaps fixed some of the
> issues in the OP's program.
>

True, but it would add many other challenges - not least of which no
mainstream C compiler supports them. "int64_t" and "uint64_t", however,
/are/ well supported.

> >
> > Of course there will be situations when 32-bit types will be faster
> than 64-bit types - such decisions are based on statistical information
> and common patterns, and will never be perfect in all circumstances.
> >
> >> (If I look at the actual stdint.h for mingw, int16_t is just
> 'short'. On my WSL, inside /usr/include/stdint.h, it is defined on top
> of long, which may be 32 or 64 bits.)
> >>
> >
> > "int16_t" must be exactly 16 bits, and many <stdint.h> files will
> define it based on "short int".  It will not be based on "long", unless
> using some unusual compiler extensions.  (In the AVR port of gcc, the
> usual <stdint.h> defines all the types as typedefs of "int" with gcc
> attributes to control the size.  I don't know why it does that, and I
> haven't seen it elsewhere.)
>
> Sorry, I meant 'int_fast16_t' was defined as 'short' on mingw and 'long'
> on WSL.
>

OK.

Of course, the <stdint.h> headers are tied tightly to the
implementation, and are not intended to be portable across systems - the
"mingw" folks know the size of "long" on their target and can rely on
that. They don't have to be concerned about it being 32-bit on some
platforms and 64-bit on others.

The smarter thing to do, at least for GCC, is to use the built-in
pre-defined types like "__INT_FAST16_TYPE__". These are pre-defined by
the compiler, precisely to make the implementation of <stdint.h> easy,
reliable and portable across targets.

Ben Bacarisse

unread,
Nov 3, 2023, 6:11:07 AM11/3/23
to
My feeling is that it's the "proper" encryption that has to be
efficient -- encrypting all hard drive traffic, backups, net
communication, bulk emails and so on. The "good enough" sort can
probably be inefficient.

--
Ben.

David Brown

unread,
Nov 3, 2023, 10:01:42 AM11/3/23
to
Ideally, it's /all/ efficient :-)

Efficient encryption is almost always done with symmetric ciphers - the
same key is used to lock and unlock the data. Asymmetric ciphers are
invariably much more demanding, and are thus used either for very
important encryption, public/private authentication, or to get a secure
exchange of a long random key for a symmetric cipher.

Within the class of symmetric ciphers, there is a lot of possibilities,
and there are balances between efficiency and security, especially when
"efficiency" can be in terms of hardware implementations, software on
big systems, software on small systems, and streaming or block-oriented,
to name just some aspects.

You are absolutely correct that for some uses, high security /and/ high
efficiency is important. You want your disk encryption or VPN traffic
to be secure but not cause too much slowdown for normal use. But there
are always tradeoffs here.

In cases where efficiency is not an issue, it is often actually easier
to use standardised solid encryption systems. Find a solid AES,
Blowfish or similar implementation for your chosen programming language,
and use that. The main reason why you'd want a quick and simple scheme
(other than for fun or learning) is because your target can't run such
standard algorithms fast enough for your needs (or perhaps, due to
limited memory, it can't run it at all).

Scott Lurndal

unread,
Nov 3, 2023, 12:52:54 PM11/3/23
to
Generally hardware implementations are preferable for performance
(e.g. inline IPSEC on 100- or 400-Gb/sec ethernet ports).

Chris M. Thomasson

unread,
Nov 3, 2023, 6:11:36 PM11/3/23
to
;^D

A C impl of my experimental scheme:

https://pastebin.com/raw/feUnA3kP

Ivvvvho, it can be "simple" because I am using the following HMAC lib
that does most of the heavy lifting for me:

https://github.com/ogay/hmac

I did not feel like coding up HMAC from scratch.

Chris M. Thomasson

unread,
Nov 3, 2023, 6:12:44 PM11/3/23
to
Hardware HMAC would make my experiment go a lot faster...

Chris M. Thomasson

unread,
Nov 4, 2023, 2:57:33 AM11/4/23
to
On 11/2/2023 12:02 PM, David Brown wrote:
Fwiw, a friend of mine did a little write up of one of my algorithms
over here:

https://paulbourke.net/fractals/multijulia

Paul is a very smart guy, and so are you and Ben, a lot of people on
this group. The spam has went down to zero for me so far... ;^)

Chris M. Thomasson

unread,
Nov 4, 2023, 3:11:46 AM11/4/23
to

Chris M. Thomasson

unread,
Nov 9, 2023, 4:17:14 AM11/9/23
to
On 10/30/2023 2:01 PM, Chris M. Thomasson wrote:
> This has to be undefined behavior. Check it out:
>
> Here is my C code for a fun toy experimental fractal:
>
> https://pastebin.com/raw/fcV5YiJH
> (raw link to text...)[...]

I will get back into this, got caught up with some other work right now.

Tim Rentsch

unread,
Nov 9, 2023, 6:55:22 PM11/9/23
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> Richard Harnden <richard...@gmail.invalid> writes:
>
>> On 30/10/2023 21:01, Chris M. Thomasson wrote:
>>
>>> https://pastebin.com/raw/fcV5YiJH
>>
>> $ gcc -std=c99 -pedantic -W -Wall -fsanitize=undefined -O2 -lm ffe.c

>> ffe.c:305:18: warning: taking the absolute value of unsigned type
>> 'unsigned int' has no effect [-Wabsolute-value]
>> ec = abs(icount - ec);
>> ^
>> ffe.c:305:18: note: remove the call to 'abs' since unsigned values
>> cannot be negative
>> ec = abs(icount - ec);
>> ^~~
>> 1 warning generated.
>>
>> If you follow that advise, then it doesn't decrypt.
>
> That's "compiler" advice! While icount - ec is indeed unsigned,
> the conversion to int (the argument type of abs) is sometimes
> undefined due to overflow.

Converting an unsigned int to int is implementation-defined, not
undefined. (The C standard also allows an implementation-defined
signal to be raised, but it's unlikely either gcc or clang does
so.)

> So removing the call is fine in the eyes of a compiler because the
> result will be the same in the defined cases and compilers don't
> care about the undefined ones.

The compiler is giving stupid advice. The result is defined in
all cases, except for when the (post-conversion) argument value
happens to be INT_MIN. Unless the implementation-defined rule
for converting an unsigned int to an int is very strange,
removing the call changes the program's semantics.

Chris M. Thomasson

unread,
Nov 11, 2023, 12:02:45 AM11/11/23
to
On 10/30/2023 2:01 PM, Chris M. Thomasson wrote:
> This has to be undefined behavior. Check it out:
>
> Here is my C code for a fun toy experimental fractal:
>
> https://pastebin.com/raw/fcV5YiJH
> (raw link to text...)
[...]

I want to mix this into:

https://groups.google.com/g/comp.lang.c++/c/bB1wA4wvoFc/m/GdzmMd41AQAJ

Humm...

0 new messages