Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document / assert non-portable assumptions #792

Open
real-or-random opened this issue Aug 8, 2020 · 9 comments
Open

Document / assert non-portable assumptions #792

real-or-random opened this issue Aug 8, 2020 · 9 comments

Comments

@real-or-random
Copy link
Contributor

I think it's reasonable to require a two's complement implementation (we could verify it in a configure script, and in unit tests)

If you really have some exotic system, then you might not run ./configure or the tests either. I think the safest way is to use some C static assert hack e.g., https://stackoverflow.com/a/56742411. These looks very ugly but they work and the ugliness is hidden behind a macro. We should also check other simple assumptions such as sizeof(int) == 4 etc. Alternatively, we could perform some self-tests at context creation time, and call the error callback if they fail. The simple ones will be optimized away by the compiler, and we should have some kind of self-test anyway if we want to implement a SHA256 override (see the discussion in #702).

Originally posted by @real-or-random in #767 (comment)

@gmaxwell notes there that the static assert hack may not be the best idea.

@real-or-random
Copy link
Contributor Author

real-or-random commented Aug 8, 2020

(edit: keeping a up-to-date list here)

  • Right shifts
    int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
  • size of size_t, see for example
    * The following limitations are known, and there are probably more:
    (also in contrib, see https://github.com/bitcoin/bitcoin/pull/10657/files)
  • sizeof(int) <= 4, otherwise uint32_t x uint32_t multiplication could result in signed overflow (This is even absurder when you state it this way.)
  • if we're pedantic then maybe also CHAR_BITS
  • endianness (cannot be checked at compile-time, a SHA256 self-test would cover this unless we have a SHA256 override)
  • I would not be surprised if we assume sizeof(int) >= 4 somewhere.

This is a shot in the dark but @roconnor-blockstream do you know some more?

@gmaxwell
Copy link
Contributor

size of size_t, see for example

Might be better to make that config macro get size_t's bits and base the limit on that. Otherwise its reducing portability for unexposed configurability.

@real-or-random
Copy link
Contributor Author

size of size_t, see for example

Might be better to make that config macro get size_t's bits and base the limit on that. Otherwise its reducing portability for unexposed configurability.

Sorry, I can't follow. Which macro?

@gmaxwell
Copy link
Contributor

#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24
the window_size absurd maximum of 24 is driven by size_t overflow.

@practicalswift
Copy link
Contributor

Here are some assumptions that come to my mind immediately:

This is a shot in the dark but @roconnor-blockstream do you know some more?

FWIW, these assumptions are asserted in Bitcoin Core:

https://github.com/bitcoin/bitcoin/blob/master/src/compat/assumptions.h

@gmaxwell
Copy link
Contributor

gmaxwell commented Aug 16, 2020

I would not be surprised if we assume sizeof(int) >= 4 somewhere

Nope, test_fixed_wnaf_small has some bugs where it uses 32-bit values as int arguments, but other than that and the multi-ecmult tests (which need some fixes to reduce memory usage before I can tests) the tests pass on a 16-bit platform. (nor have I run recovery or ecdh tests yet, but -- generally seems like it works)

@real-or-random
Copy link
Contributor Author

We have a SHA256 self-test now (#799).

@real-or-random
Copy link
Contributor Author

real-or-random commented Sep 17, 2020

#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24

the window_size absurd maximum of 24 is driven by size_t overflow.

I tried to make that work but it's not that easy. In the precompiler we don't have sizeof (and we can't emulate it because struct padding is unknown etc). In the static assert hack, we can't check for overflow. Maybe it's best to simply set the maximum to something like 10 if SIZE_MAX is smaller than UINT32_MAX. That's not precise but should be good enough in practice. What window size did you use for your 16-bit tests?

Nope, test_fixed_wnaf_small has some bugs where it uses 32-bit values as int arguments

Are you willing to fix these?

@real-or-random
Copy link
Contributor Author

ok @roconnor-blockstream suggests something along the lines of

ECMULT_TABLE_SIZE(WINDOW_G) <= SIZE_MAX / sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g)[0]).

Indeed, this should do it if we additionally check that the shift within ECMULT_TABLE_SIZE does neither overflow int nor size_t (the code uses size_t for memory sizes but then int for array indices).

real-or-random added a commit that referenced this issue Sep 26, 2020
c0041b5 Add static assertion that uint32_t is unsigned int or wider (Tim Ruffing)

Pull request description:

  Solves one item in #792 .

ACKs for top commit:
  sipa:
    utACK c0041b5
  elichai:
    ACK c0041b5

Tree-SHA512: 9f700e89be39e15983260da94642593d16b9c437171e10377837ac73731ca7ba5dd7e328b3d93d0a24d143fb9e73abd11c578f6b58e2f94c82b783e977173b0c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants
@gmaxwell @real-or-random @practicalswift and others