Change SHA256 byte counter from size_t to uint64_t #731

pull real-or-random wants to merge 4 commits into bitcoin-core:master from real-or-random:202003-sha-size_t changing 3 files +139 −13
  1. real-or-random commented at 12:13 pm on March 31, 2020: contributor

    This avoids that the SHA256 implementation would produce wrong paddings and thus wrong digests for messages of length >= 2^32 bytes on 32-bit platforms.

    This is not exploitable in any way since the SHA256 API is an internal API and we never call it with that long messages.

    This also simplifies the struct initializer for the padding. Since missing elements are initialized with zeros, this change is purely syntactical.

  2. elichai commented at 9:06 am on April 1, 2020: contributor
    Looks good. ACK 33d0871ee77cd7014e40abf39ac6da98114b3558
  3. real-or-random commented at 12:37 pm on April 16, 2020: contributor

    I added a commit with additional tests for very long messages. See the commit message. This adds 6s on my machine. I think this is acceptable. It would be nice if someone with access to a 32bit machine can try to revert my fix ( f5fdba8 ) and verify that the new tests fail then.

    It will be good to have an additional test for crossing the 2^32 byte (instead of bit) boundary but this will take very long to execute. So I think it’s better to implement (better) support for setting midstates first which is anyway useful for Schnorr signatures. Then we can add such a test.

    Note to myself for a future PR for setting midstates: cloudtools/sha256 is a python library for playing around with midstates. It’s similarly broken to our implementation but the fix is easy. https://github.com/cloudtools/sha256/pull/3

  4. jonasnick commented at 7:22 am on April 20, 2020: contributor

    Good catch! This should be fixed.

    Adding six seconds with a test would be very painful. I don’t see why it’s needed. You could simply initialize the sha struct with a known midstate and bytes value (like this? https://github.com/bitcoin-core/secp256k1/pull/558/commits/e85b0bbafc31de2b746205e970753968b51ddd1b#diff-0d77700fa6e05639431c962ffaa5365aR437) and then do a single compression round to test that bytes doesn’t wrap around. You should be able to test this with the -m32 compiler flag even on 64 bit architectures.

  5. real-or-random force-pushed on Apr 22, 2020
  6. real-or-random commented at 9:48 am on April 22, 2020: contributor

    Adding six seconds with a test would be very painful. I don’t see why it’s needed. You could simply initialize the sha struct with a known midstate and bytes value (like this? e85b0bb#diff-0d77700fa6e05639431c962ffaa5365aR437) and then do a single compression round to test that bytes doesn’t wrap around.

    I added tests that implement this suggestion. On the way, I introduced a (very simply) initialize_midstate function to the internal API and changed the initialization functions to simple struct assignments. This feels a little bit cleaner and simpler to me.

    See the commit messages for details on the new tests.

    I left the other test commit there because it also cleans up the code and it works. But I left the extremely long message commented.

    You should be able to test this with the -m32 compiler flag even on 64 bit architectures.

    Ah sure, I verified that the test fails then (even with the VERIFY_CHECK for overflow in hash_impl.h deleted).

  7. real-or-random force-pushed on Apr 22, 2020
  8. real-or-random commented at 10:03 am on April 22, 2020: contributor
    This uses constants syntax as in #746. I can change this of course if we don’t want #746.
  9. in src/tests.c:421 in b602b7bec5 outdated
    419+        /*  Uncomment for test with extremely long input message. */
    420+        /*, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" */
    421     };
    422-    static const unsigned char outputs[8][32] = {
    423+    static const unsigned int repeat[] = {
    424+        1, 1, 1, 1, 1, 1, 1, 1, 1000000/5, 16777216
    


    jonasnick commented at 8:55 pm on April 22, 2020:
    What’s the significance of the 1000000/5 “aaa” test?

    real-or-random commented at 11:08 am on April 23, 2020:
    It’s not particularly significant. It’s a 1 million bytes test. It’s also taken from https://www.di-mgt.com.au/sha_testvectors.html, see the commit message. I left it in because I can’t notice a difference of test running time in practice and it won’t hurt.

    jonasnick commented at 10:22 am on October 27, 2020:
    The difference is about 3 seconds (10%) in normal, no valgrind, tests.

    real-or-random commented at 9:03 pm on January 24, 2022:
    This should use the CONDITIONAL_TEST introduced in #1049 .

    real-or-random commented at 12:11 pm on March 7, 2022:
    fixed
  10. jonasnick commented at 9:06 pm on April 22, 2020: contributor
    Can confirm that the new counter_tests catch the issue (in particular with the correct test case number 12).
  11. real-or-random added this to the milestone initial release (1.0.0-rc.1) on May 8, 2020
  12. in src/tests.c:555 in b602b7bec5 outdated
    473             CHECK(memcmp(out, outputs[i], 32) == 0);
    474         }
    475     }
    476 }
    477 
    478+void run_sha256_counter_tests(void) {
    


    jonasnick commented at 10:28 am on October 27, 2020:

    Would make sense to add a comment here that there exists code that generates this and where it is.

    Fwiw I can’t run it. After installing sha256 with pip I get the error

    0Traceback (most recent call last):
    1  File "py.py", line 22, in <module>
    2    hasher_copy = copy(hasher)
    3  File "/usr/lib/python3.8/copy.py", line 92, in copy
    4    rv = reductor(4)
    5TypeError: cannot pickle 'sha256.sha256' object
    

    That’s why everyone should use nix by the way :) I don’t think it’s particularly important to recreate the test cases as they shouldn’t change and it’s unlikely that we want to add more (otherwise I would have also suggested to move the code from the commit message into the contrib directory).


    sipa commented at 6:24 pm on October 27, 2020:
    I get the same error.

    real-or-random commented at 12:16 pm on March 7, 2022:
    Maybe retry pip install sha256. They recently released a new version which claims to have Python 3 support. Maybe that fixes the problem (though I have no idea why this was working for me….)

    jonasnick commented at 3:05 pm on March 22, 2022:
    Works for me now (python 3).
  13. jonasnick commented at 10:29 am on October 27, 2020: contributor

    This looks good to me. Needs a rebase. Perhaps also use this new midstate api in other parts of the code, like the schnorrsig module.

    Regarding the commit message “Those tests verify that the SHA256 bit counter wraps correctly at bit lengths 20 to 34.”. Wouldn’t it be better to say “increments” instead of “wraps”?

  14. in src/hash.h:21 in 6823d3ba67 outdated
    15@@ -16,7 +16,13 @@ typedef struct {
    16     uint64_t bytes;
    17 } secp256k1_sha256;
    18 
    19+
    20+static const secp256k1_sha256 secp256k1_sha256_initial_state = {
    21+    {UINT32_C(0x6a09e667), UINT32_C(0xbb67ae85), UINT32_C(0x3c6ef372), UINT32_C(0xa54ff53a), UINT32_C(0x510e527f), UINT32_C(0x9b05688c), UINT32_C(0x1f83d9ab), UINT32_C(0x5be0cd19)},
    


    sipa commented at 6:21 pm on October 27, 2020:
    Nit: I don’t think these UINT32_C contribute anything. Integer constants take on a type that fits them, up to long / unsigned long, which are IIRC guaranteed to be at least 32 bits.

    real-or-random commented at 12:11 pm on March 7, 2022:
    fixed
  15. practicalswift commented at 9:43 am on October 29, 2020: contributor

    Concept ACK

    Somewhat related: https://github.com/bitcoin/bitcoin/issues/19930 (Signed integer overflow when SipHasher processes inputs >= 2 GB)

  16. jonasnick commented at 2:28 pm on November 4, 2020: contributor
    Needs rebase again.
  17. in src/hash_impl.h:152 in b602b7bec5 outdated
    148+    static const unsigned char pad[64] = {0x80};
    149     uint32_t sizedesc[2];
    150     uint32_t out[8];
    151     int i = 0;
    152+    /* The maximum message size of SHA256 is 2^64-1 bits. */
    153+    VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 56));
    


    siv2r commented at 0:49 am on December 12, 2021:
    shouldn’t this be (unint64_t)1 << 61? ((2^64)/8 bytes)

    real-or-random commented at 12:52 pm on December 14, 2021:
    oh indeed.

    real-or-random commented at 12:11 pm on March 7, 2022:
    fixed
  18. siv2r commented at 1:18 am on December 12, 2021: contributor
    ACK b602b7b, make check passes all tests. The values of the three new test vectors added are correct. I verified their values using python’s hashlib module.
  19. real-or-random cross-referenced this on Dec 26, 2021 from issue Faster fixed-input ecmult tests by sipa
  20. Change SHA256 byte counter from size_t to uint64_t
    This avoids that the SHA256 implementation would produce wrong paddings
    and thus wrong digests for messages of length >= 2^32 bytes on 32-bit
    platforms.
    
    This is not exploitable in any way since the SHA256 API is an internal
    API and we never call it with that long messages.
    eb28464a8b
  21. Simplify struct initializer for SHA256 padding
    Since missing elements are initialized with zeros, this change is
    purely syntactical.
    8e3dde1137
  22. Add test vector for very long SHA256 messages
    The vector has been taken from https://www.di-mgt.com.au/sha_testvectors.html.
    It can be independently verified using the following Python code.
    
    ```
    h = hashlib.sha256()
    for i in range(1_000_000):
        h.update(b'a')
    print(h.hexdigest())
    ```
    9b514ce1d2
  23. real-or-random force-pushed on Mar 7, 2022
  24. real-or-random force-pushed on Mar 7, 2022
  25. real-or-random commented at 12:15 pm on March 7, 2022: contributor
    Ready for review again. I removed some questionable parts of this PR (including the new internal function to set a midstate which simply took a full sha256 state struct – tests now simply set the state explicitly).
  26. real-or-random force-pushed on Mar 7, 2022
  27. real-or-random commented at 12:46 pm on March 7, 2022: contributor
    Forced push to fix the CI failure.
  28. in src/tests.c:527 in a1a9e696cf outdated
    532+from sha256 import sha256
    533+from copy import copy
    534+
    535+def midstate_c_definition(hasher):
    536+    ret  = '    {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n'
    537+    ret += '    {0x00}, ' + str(hasher.state[1]) + '}'
    


    jonasnick commented at 3:06 pm on March 22, 2022:
    0    ret += '    {0x00}, ' + hex(str(hasher.state[1])) + '}'
    

    is required to get the same output as the test vectors in tests.c


    real-or-random commented at 9:53 am on March 23, 2022:
    oh fixed.
  29. in src/tests.c:513 in a1a9e696cf outdated
    518     }
    519 }
    520 
    521+/** SHA256 bit counter tests
    522+
    523+The tests verify that the SHA256 bit counter doesn't wrap around at bit lengths
    


    jonasnick commented at 3:09 pm on March 22, 2022:
    0The tests verify that the SHA256 bit counter doesn't wrap around at byte lengths
    

    real-or-random commented at 9:53 am on March 23, 2022:
    Ah yes, I reworded the sentence to make this even clearer.

    jonasnick commented at 1:05 pm on March 23, 2022:
    yeah, much better
  30. jonasnick commented at 3:11 pm on March 22, 2022: contributor
    concept ACK, can confirm that “counter_test” for the 2^32 byte boundary (number 12) fails when reverting the counter fix and building a 32-bit binary.
  31. real-or-random force-pushed on Mar 23, 2022
  32. real-or-random commented at 9:57 am on March 23, 2022: contributor

    can confirm that “counter_test” for the 2^32 byte boundary (number 12) fails when reverting the counter fix and building a 32-bit binary.

    By the way , a nice thing is that the pure existence of the tests will make the compiler warn in the case of a 32-bit counter (because the tests will then try to set a too large constant for the counter).

  33. in src/tests.c:514 in da38fb7cf2 outdated
    519 }
    520 
    521+/** SHA256 counter tests
    522+
    523+The tests verify that the SHA256 counter doesn't wrap around at message lengths
    524+20^i bytes to 33^i bytes. This wide range aims at being independent of the
    


    jonasnick commented at 1:06 pm on March 23, 2022:
    shouldn’t this be 2^20 bytes and 2^33 bytes?

    real-or-random commented at 3:34 pm on March 23, 2022:
    should now really be fixed
  34. Add SHA256 bit counter tests f8d9174357
  35. real-or-random force-pushed on Mar 23, 2022
  36. jonasnick commented at 4:03 pm on March 23, 2022: contributor
    ACK f8d9174357391ab4bf65a2f4d9d9cfb8039dc592
  37. sipa commented at 9:35 pm on March 24, 2022: contributor
    utACK f8d9174357391ab4bf65a2f4d9d9cfb8039dc592
  38. real-or-random merged this on Mar 24, 2022
  39. real-or-random closed this on Mar 24, 2022

  40. fanquake referenced this in commit 465d05253a on Mar 30, 2022
  41. real-or-random referenced this in commit 6c0aecf72b on Apr 1, 2022
  42. fanquake referenced this in commit afb7a6fe06 on Apr 6, 2022
  43. gwillen referenced this in commit 35d6112a72 on May 25, 2022
  44. patricklodder referenced this in commit 21badcf9d2 on Jul 25, 2022
  45. patricklodder referenced this in commit 03002a9013 on Jul 28, 2022
  46. janus referenced this in commit 3a0652a777 on Aug 4, 2022
  47. real-or-random cross-referenced this on Aug 9, 2022 from issue BIP340: Variable-length messages / domain separation by real-or-random
  48. real-or-random cross-referenced this on Dec 19, 2022 from issue Unnecessary call to secp256k1_sha256_initialize by Coding-Enthusiast
  49. str4d referenced this in commit 522190d5c3 on Apr 21, 2023
  50. vmta referenced this in commit e1120c94a1 on Jun 4, 2023
  51. vmta referenced this in commit 8f03457eed on Jul 1, 2023


real-or-random elichai jonasnick sipa practicalswift siv2r

Milestone
stable release (1.0.0-rc.1)


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/secp256k1. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-23 00:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me