field: serialize elements by word #1889

pull l0rinc wants to merge 1 commits into bitcoin-core:master from l0rinc:l0rinc/field-5x52-serialize-word changing 2 files +12 −64
  1. l0rinc commented at 1:28 AM on July 13, 2026: contributor

    Problem: Both field implementations serialize normalized elements with 32 separate byte assignments in secp256k1_fe_impl_get_b32. They were introduced in #437 to unroll nested nibble loops for performance. At the time, the endian write helpers did not exist, so the unrolling was expressed directly.

    Fix: Keep both serializers unrolled by packing the 5x52 limbs into four 64-bit words and the 10x26 limbs into eight 32-bit words, then reuse the corresponding endian write helper. This matches the existing 4x64 and 8x32 scalar serializers. The serialized output is unchanged for normalized inputs, and benchmarks indicate no measurable performance regression.

    Testing: Existing field conversion and reduced-boundary tests compare the serialized bytes directly. Compiler Explorer compares the exact before and after serializers with GCC 16.1 and Clang 22.1 at -O2, in both native and -m32 modes.

    <details><summary>Benchmarks</summary>

    for cc in gcc clang; do \
      echo; $cc --version | head -1; \
      CC=$cc cmake -B build-$cc -GNinja -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 && \
      CC=$cc cmake -B build-$cc-10x26 -GNinja -DCMAKE_BUILD_TYPE=Release -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int64 >/dev/null 2>&1 && \
      for build in build-$cc build-$cc-10x26; do \
        echo; echo $build; \
        for rev in ebf594320dc838b9de1abb54d5ba98cef84f4297 e217ead5c46062ecda964ba858f7518b7e3bb5e7; do \
          git fetch origin -q $rev && git checkout -q $rev && \
          ninja -C $build bench >/dev/null 2>&1 && \
          echo $rev && \
          SECP256K1_BENCH_ITERS=10000 $build/bin/bench; \
        done; \
      done; \
    done
    
    gcc (Ubuntu 15.2.0-16ubuntu1) 15.2.0
    
    build-gcc
    ebf594320dc838b9de1abb54d5ba98cef84f4297
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    33.9       ,    34.0       ,    34.0
    ecdsa_sign                    ,    21.6       ,    21.6       ,    21.6
    ec_keygen                     ,    15.2       ,    15.2       ,    15.3
    ecdh                          ,    33.4       ,    33.5       ,    33.5
    schnorrsig_sign               ,    16.1       ,    16.1       ,    16.2
    schnorrsig_verify             ,    34.3       ,    34.3       ,    34.4
    ellswift_encode               ,    16.2       ,    16.2       ,    16.2
    ellswift_decode               ,     7.21      ,     7.22      ,     7.24
    ellswift_keygen               ,    31.5       ,    31.5       ,    31.5
    ellswift_ecdh                 ,    36.0       ,    36.1       ,    36.1
    e217ead5c46062ecda964ba858f7518b7e3bb5e7
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    34.0       ,    34.1       ,    34.4
    ecdsa_sign                    ,    21.6       ,    21.6       ,    21.6
    ec_keygen                     ,    15.3       ,    15.3       ,    15.3
    ecdh                          ,    33.3       ,    33.4       ,    33.6
    schnorrsig_sign               ,    16.1       ,    16.1       ,    16.2
    schnorrsig_verify             ,    34.4       ,    34.4       ,    34.5
    ellswift_encode               ,    16.3       ,    16.3       ,    16.3
    ellswift_decode               ,     7.24      ,     7.24      ,     7.25
    ellswift_keygen               ,    31.5       ,    31.6       ,    31.7
    ellswift_ecdh                 ,    36.0       ,    36.1       ,    36.1
    
    build-gcc-10x26
    ebf594320dc838b9de1abb54d5ba98cef84f4297
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    58.4       ,    58.5       ,    58.5
    ecdsa_sign                    ,    29.7       ,    29.8       ,    29.8
    ec_keygen                     ,    22.3       ,    22.4       ,    22.5
    ecdh                          ,    56.0       ,    56.1       ,    56.2
    schnorrsig_sign               ,    23.4       ,    23.4       ,    23.5
    schnorrsig_verify             ,    58.9       ,    59.0       ,    59.1
    ellswift_encode               ,    22.7       ,    22.7       ,    22.7
    ellswift_decode               ,    10.8       ,    10.8       ,    10.8
    ellswift_keygen               ,    45.1       ,    45.2       ,    45.3
    ellswift_ecdh                 ,    59.6       ,    59.7       ,    59.8
    e217ead5c46062ecda964ba858f7518b7e3bb5e7
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    58.5       ,    58.6       ,    58.7
    ecdsa_sign                    ,    29.8       ,    29.8       ,    29.9
    ec_keygen                     ,    22.3       ,    22.4       ,    22.4
    ecdh                          ,    56.0       ,    56.1       ,    56.4
    schnorrsig_sign               ,    23.5       ,    23.5       ,    23.5
    schnorrsig_verify             ,    58.9       ,    59.0       ,    59.1
    ellswift_encode               ,    22.9       ,    22.9       ,    22.9
    ellswift_decode               ,    10.8       ,    10.8       ,    10.8
    ellswift_keygen               ,    45.2       ,    45.3       ,    45.4
    ellswift_ecdh                 ,    59.6       ,    59.8       ,    59.9
    
    Ubuntu clang version 21.1.8 (6ubuntu1)
    
    build-clang
    ebf594320dc838b9de1abb54d5ba98cef84f4297
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    36.2       ,    36.3       ,    36.7
    ecdsa_sign                    ,    23.1       ,    23.1       ,    23.2
    ec_keygen                     ,    16.6       ,    16.7       ,    16.7
    ecdh                          ,    35.6       ,    35.7       ,    35.7
    schnorrsig_sign               ,    17.6       ,    17.6       ,    17.6
    schnorrsig_verify             ,    36.6       ,    36.7       ,    36.9
    ellswift_encode               ,    16.6       ,    16.6       ,    16.7
    ellswift_decode               ,     7.28      ,     7.29      ,     7.30
    ellswift_keygen               ,    33.2       ,    33.2       ,    33.3
    ellswift_ecdh                 ,    38.5       ,    38.5       ,    38.6
    e217ead5c46062ecda964ba858f7518b7e3bb5e7
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    35.5       ,    35.6       ,    35.8
    ecdsa_sign                    ,    23.0       ,    23.1       ,    23.2
    ec_keygen                     ,    16.6       ,    16.7       ,    16.8
    ecdh                          ,    35.7       ,    35.7       ,    35.8
    schnorrsig_sign               ,    17.6       ,    17.6       ,    17.7
    schnorrsig_verify             ,    35.9       ,    35.9       ,    36.0
    ellswift_encode               ,    16.4       ,    16.4       ,    16.4
    ellswift_decode               ,     7.22      ,     7.22      ,     7.23
    ellswift_keygen               ,    33.0       ,    33.0       ,    33.1
    ellswift_ecdh                 ,    38.5       ,    38.6       ,    38.8
    
    build-clang-10x26
    ebf594320dc838b9de1abb54d5ba98cef84f4297
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    64.2       ,    64.3       ,    64.7
    ecdsa_sign                    ,    33.8       ,    33.9       ,    33.9
    ec_keygen                     ,    26.3       ,    26.3       ,    26.3
    ecdh                          ,    63.4       ,    63.6       ,    63.8
    schnorrsig_sign               ,    27.2       ,    27.3       ,    27.3
    schnorrsig_verify             ,    64.5       ,    64.6       ,    64.7
    ellswift_encode               ,    22.1       ,    22.1       ,    22.1
    ellswift_decode               ,    10.6       ,    10.6       ,    10.7
    ellswift_keygen               ,    48.3       ,    48.3       ,    48.5
    ellswift_ecdh                 ,    67.0       ,    67.0       ,    67.1
    e217ead5c46062ecda964ba858f7518b7e3bb5e7
    Benchmark                     ,    Min(us)    ,    Avg(us)    ,    Max(us)
    
    ecdsa_verify                  ,    63.9       ,    64.0       ,    64.3
    ecdsa_sign                    ,    33.8       ,    33.9       ,    34.0
    ec_keygen                     ,    26.3       ,    26.3       ,    26.3
    ecdh                          ,    62.5       ,    62.5       ,    62.6
    schnorrsig_sign               ,    27.2       ,    27.3       ,    27.4
    schnorrsig_verify             ,    64.1       ,    64.2       ,    64.2
    ellswift_encode               ,    22.1       ,    22.2       ,    22.3
    ellswift_decode               ,    10.6       ,    10.7       ,    10.7
    ellswift_keygen               ,    48.4       ,    48.4       ,    48.6
    ellswift_ecdh                 ,    66.2       ,    66.3       ,    66.4
    

    </details>

  2. real-or-random commented at 6:56 AM on July 13, 2026: contributor

    Concept ACK -- it makes the code a tiny bit shorter and more readable

    Can we do the same for the 10x26 impl?

  3. real-or-random added the label tweak/refactor on Jul 13, 2026
  4. field: serialize elements by word
    The byte assignments replaced nested nibble loops before the endian write helpers existed.
    Pack the 5x52 limbs into four 64-bit words and the 10x26 limbs into eight 32-bit words, then use those helpers.
    This matches the scalar serializers and keeps the output unchanged.
    Benchmarks indicate no measurable performance regression.
    e217ead5c4
  5. l0rinc renamed this:
    field: serialize 5x52 elements by word
    field: serialize elements by word
    on Jul 13, 2026
  6. l0rinc force-pushed on Jul 13, 2026
  7. l0rinc commented at 5:24 PM on July 13, 2026: contributor

    Done, thanks! Also extended the Godbolt reproducer with the 32-bit version and added the GCC/Clang benchmarks to the description as further proof that it's a safe refactor.

  8. real-or-random approved
  9. real-or-random commented at 7:41 PM on July 13, 2026: contributor

    utACK e217ead5c46062ecda964ba858f7518b7e3bb5e7

  10. theStack approved
  11. theStack commented at 10:45 PM on July 17, 2026: contributor

    ACK e217ead5c46062ecda964ba858f7518b7e3bb5e7

  12. theStack merged this on Jul 17, 2026
  13. theStack closed this on Jul 17, 2026

  14. l0rinc deleted the branch on Jul 17, 2026

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: 2026-07-18 06:15 UTC

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