BIP324: CKey encode/decode to elligator-swift #23432

pull dhruv wants to merge 5 commits into bitcoin:master from dhruv:bip324-ellsq changing 30 files +2084 −18
  1. dhruv commented at 5:14 pm on November 3, 2021: contributor

    This PR adds the ability to encode CPubKey objects to their pseudorandom elligator-swift representation. Depends on https://github.com/bitcoin-core/secp256k1/pull/1129.

    The first 2 commits enable the availability of that upstream code and will be removed once https://github.com/bitcoin-core/secp256k1/pull/1129 is merged. Only last 3 commits need review here.

  2. dhruv force-pushed on Nov 3, 2021
  3. DrahtBot added the label Build system on Nov 3, 2021
  4. DrahtBot added the label Upstream on Nov 3, 2021
  5. DrahtBot added the label Utils/log/libs on Nov 3, 2021
  6. dhruv force-pushed on Nov 3, 2021
  7. dhruv force-pushed on Nov 3, 2021
  8. dhruv force-pushed on Nov 4, 2021
  9. DrahtBot commented at 8:33 am on November 4, 2021: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK stratospher

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #27445 (Update src/secp256k1 subtree to release v0.3.1 by sipa)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  10. dhruv force-pushed on Nov 4, 2021
  11. hebasto commented at 9:20 am on November 5, 2021: member

    Wrt a failed Win64 cross-compiled build.

    I’ve managed to successfully link libbitcoinconsensus.la with the following patch:

     0--- a/src/Makefile.am
     1+++ b/src/Makefile.am
     2@@ -507,8 +507,6 @@ libbitcoin_consensus_a_SOURCES = \
     3   primitives/transaction.h \
     4   pubkey.cpp \
     5   pubkey.h \
     6-  random.cpp \
     7-  random.h \
     8   script/bitcoinconsensus.cpp \
     9   script/interpreter.cpp \
    10   script/interpreter.h \
    11@@ -743,7 +741,7 @@ include_HEADERS = script/bitcoinconsensus.h
    12 libbitcoinconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
    13 
    14 libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
    15-libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1)
    16+libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) $(LIBBITCOIN_UTIL) $(BOOST_LIBS)
    17 libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
    18 libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
    19 
    

    Obviously, this workaround is suboptimal:

    0  CXXLD    libbitcoinconsensus.la
    1
    2*** Warning: Linking the shared library libbitcoinconsensus.la against the
    3*** static library libbitcoin_util.a is not portable!
    

    For better approach, probably source code re-organization should be considered.

  12. in src/pubkey.cpp:348 in aa8ab68f6b outdated
    343+    if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
    344+        return {};
    345+    }
    346+
    347+    uint8_t r32[32];
    348+    GetStrongRandBytes(r32, 32);
    


    sipa commented at 5:02 am on November 6, 2021:

    It’s a pretty unfortunate I think that the whole random module needs to be included in libbitcoinconsensus just because it include pubkey (which then wouldn’t be part of libbitcoinconsensus), and this adds a dependency on randomness to pubkey.

    Alternatives are putting the conversion between pubkey and ellsq encoding in a different modulo than pubkey, or passing in randomness explicitly as argument to EllSqEncode.

    Also, it’s overkill to use strong random bytes here.


    dhruv commented at 8:07 pm on November 6, 2021:
    Done. Passing in random bytes to EllSqEncode now.
  13. in src/pubkey.cpp:355 in aa8ab68f6b outdated
    350+    EllSqPubKey encoded_pubkey;
    351+    secp256k1_ellsq_encode(secp256k1_context_verify, encoded_pubkey.data(), r32, &pubkey);
    352+    return encoded_pubkey;
    353+}
    354+
    355+CPubKey::CPubKey(const EllSqPubKey& encoded_pubkey, bool compressed) {
    


    sipa commented at 5:03 am on November 6, 2021:

    There is no reason to support uncompressed public keys here I think.

    EDIT: added a missing negation


    dhruv commented at 8:07 pm on November 6, 2021:
    Done.
  14. dhruv force-pushed on Nov 6, 2021
  15. dhruv commented at 8:07 pm on November 6, 2021: contributor
    Thank you for the review and suggestions, @hebasto, @sipa. Addressed the comments, ready for further review.
  16. dhruv force-pushed on Nov 6, 2021
  17. dhruv commented at 11:30 pm on November 6, 2021: contributor

    Pushed again to fix a CI issue. I had forgotten to appropriately rollback my Makefile.am changes.

    Ready for review.

  18. laanwj added the label P2P on Nov 10, 2021
  19. dhruv force-pushed on Nov 19, 2021
  20. dhruv commented at 10:59 pm on November 19, 2021: contributor
    Removed randomness used in a fuzz test that was not derived from the fuzz seed. Ready for further review.
  21. stratospher commented at 7:31 am on November 23, 2021: contributor

    Concept ACK.

    Encoding Decoding
    Screenshot%202021-11-17%20at%207 54 51%20PM Screenshot%202021-11-17%20at%207 55 10%20PM

    This PR introduces 2 pubkey functions EllSqEncode() for encoding 33 byte/65 byte pubkey to a 64 byte Elligator square encoding and a constructor CPubKey to decode the 64 byte Elligator square encoding to a 33 byte pubkey.

    • In the unit test, a 33 byte/65 byte public key original_pubkey is computed from the private key and is fed into EllSqEncode() along with 32 random bytes to obtain 64 bytes ellsq_encoded_pubkey
    • Then decoding is done on the 64 bytes ellsq_encoded_pubkey using the CPubKey constructor to obtain a 33 bytes decoded_pubkey.
    • Finally it is checked if original_pubkey and decoded_pubkey are the same. When original_pubkey is uncompressed, the 33 bytes decoded_pubkey needs to be uncompressed to 65 bytes before the comparison.
  22. in src/test/fuzz/key.cpp:323 in 405f64ef4a outdated
    318+{
    319+    if(buffer.size() < 64) {
    320+        return;
    321+    }
    322+
    323+    auto ellsq_bytes = buffer.first(64);
    


    sipa commented at 9:32 pm on November 23, 2021:
    You could do a stronger test here: start with a pubkey drawn from the fuzz data, and if it is valid, elligator encode it (with additional randomness drawn from the fuzz data), decode it, and see if it matches the original pubkey.

    dhruv commented at 5:27 pm on November 25, 2021:
    Thanks. Done!
  23. in src/test/fuzz/key.cpp:312 in 405f64ef4a outdated
    305@@ -305,4 +306,25 @@ FUZZ_TARGET_INIT(key, initialize_key)
    306             assert(key == loaded_key);
    307         }
    308     }
    309+
    310+    {
    311+        std::array<uint8_t, 32> rnd32;
    312+        memcpy(rnd32.data(), &random_uint256, 32);
    


    maflcko commented at 9:38 pm on November 23, 2021:
    random_uint256 is uniformly distributed, making it harder for the fuzz engine to discover potential edge cases

    dhruv commented at 5:27 pm on November 25, 2021:
    Makes sense. Fixed. I ended up combining the encode/decode fuzzing.
  24. in src/test/fuzz/key.cpp:319 in 405f64ef4a outdated
    314+    }
    315+}
    316+
    317+FUZZ_TARGET_INIT(ellsq, initialize_key)
    318+{
    319+    if(buffer.size() < 64) {
    


    maflcko commented at 9:41 pm on November 23, 2021:
    You may install clang-format and run the https://github.com/bitcoin/bitcoin/tree/master/contrib/devtools#clang-format-diffpy script to preempt whitespace nitpicking.

    dhruv commented at 5:28 pm on November 25, 2021:
    Done.
  25. dhruv force-pushed on Nov 25, 2021
  26. dhruv commented at 5:28 pm on November 25, 2021: contributor
    Addressed review comments from @sipa and @MarcoFalke. Ready for further review.
  27. DrahtBot added the label Needs rebase on Dec 18, 2021
  28. dhruv force-pushed on Jan 26, 2022
  29. dhruv commented at 3:44 pm on January 26, 2022: contributor

    Rebased and updated src/secp256k1 to be up to date with the rebase on https://github.com/bitcoin-core/secp256k1/pull/982

    Ready for further review.

  30. DrahtBot removed the label Needs rebase on Jan 26, 2022
  31. dhruv commented at 5:57 pm on January 26, 2022: contributor

    The Win64 build failure is due to bringing in https://github.com/bitcoin-core/secp256k1/pull/982 (that is ahead of the subtree secp version) in the first two commits (which will not be merged with this PR). I’ll continue to investigate and ask for help on that, but it should go away when elligator-squared is brought into secp/master and updated in our subtree.

    We can continue review here in the meantime.

  32. hebasto commented at 9:08 pm on January 31, 2022: member

    The Win64 build failure…

    can be fixed with the following patch

     0--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
     1+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
     2@@ -8,6 +8,10 @@
     3     <ConfigurationType>StaticLibrary</ConfigurationType>
     4   </PropertyGroup>
     5   <ItemGroup>
     6+    <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult.c" />
     7+    <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult_gen.c" />
     8+    <ClCompile Include="..\..\src\secp256k1\src\precompute_ecmult.c" />
     9+    <ClCompile Include="..\..\src\secp256k1\src\precompute_ecmult_gen.c" />
    10     <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" />
    11   </ItemGroup>
    12   <ItemDefinitionGroup>
    

    which was suggested by @sipsorcery.

    Tested: https://cirrus-ci.com/task/5112528064741376

  33. sipa commented at 9:17 pm on January 31, 2022: member
    The precompute_ecmult.c and precompute_ecmult_gen.c shouldn’t be needed; they are for computing the tables, but the tables are checked into the repository. In fact, I’m surprised it even works with those added, as they result in multiple main() functions.
  34. sipsorcery commented at 9:22 pm on January 31, 2022: member

    In fact, I’m surprised it even works with those added, as they result in multiple main() functions.

    The msvc compiler did generate a warning about multiple main()’s. I assume it chooses the first one it finds, which of course will be problematic it it’s the wrong one.

  35. dhruv force-pushed on Feb 1, 2022
  36. dhruv commented at 11:35 pm on February 1, 2022: contributor

    Thank you for your help @sipsorcery @hebasto! I definitely would not have figured this out on my own. The suggested diff worked. @sipa, I added only precomputed_* compilation units and did not need precompute_* for the Win64 test to pass.

    Ready for further review.

  37. DrahtBot added the label Needs rebase on Apr 9, 2022
  38. dhruv force-pushed on Jun 30, 2022
  39. dhruv renamed this:
    BIP324: CPubKey encode/decode to elligator-squared
    BIP324: CPubKey encode/decode to elligator-swift
    on Jun 30, 2022
  40. dhruv commented at 10:44 pm on June 30, 2022: contributor
    Rebased. Moved to new spec’s elligator-swift instead of elligator-squared resulting in >2x speedup. Ready for further review. The linter failure will be resolved once the upstream code is in secp.
  41. DrahtBot removed the label Needs rebase on Jun 30, 2022
  42. dhruv force-pushed on Jul 22, 2022
  43. dhruv commented at 3:43 pm on July 22, 2022: contributor

    With the new integrated XDH in libsecp256k1, we no longer need to decode the elligator-swift pubkey representation in bitcoin core. In addition, this push depends on a new branch which has a modified version of elligator-swift that can encode/decode the parity of the y-coordinate while still using only 64 bytes.

    Ready for further review.

  44. in src/pubkey.cpp:349 in 9e2b88aa08 outdated
    344+    if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
    345+        return {};
    346+    }
    347+
    348+    EllSwiftPubKey encoded_pubkey;
    349+    secp256k1_ellswift_encode(secp256k1_context_verify, encoded_pubkey.data(), &pubkey, rnd32.data());
    


    sipa commented at 1:32 pm on July 23, 2022:

    I left this also as a comment on a different PR, perhaps the wrong one.

    There shouldn’t be a need to invoke secp256k1_ellswift_encode here, or have this as a method on CPubKey. The new secp256k1_ellswift_create function can go directly from private key to ellswift encoding, without needing to convert to a normal public key in the mean time. I think this would be preferable to have as a function on CKey instead, and not involve any CPubKey at all.

    secp256k1_ellswift_create is safer (doesn’t need additional randomness) and there are some (currently unimplemented) optimizations that may make it faster than the combination of secp256k1_ec_pubkey_create + secp256k1_ellswift_encode.


    dhruv commented at 7:55 pm on July 26, 2022:
    Done! Thanks for the reminder.
  45. dhruv force-pushed on Jul 26, 2022
  46. dhruv commented at 7:55 pm on July 26, 2022: contributor
    Addressed comment, ready for further review.
  47. dhruv force-pushed on Sep 11, 2022
  48. dhruv commented at 8:19 pm on September 11, 2022: contributor
    Pushed to fix a clang-tidy error discovered in a downstream PR. Ready for further review.
  49. dhruv force-pushed on Sep 29, 2022
  50. dhruv commented at 4:36 am on September 29, 2022: contributor

    Latest push:

    • Changed EllSqPubKey to be an array of std::byte instead of uint8_t to be similar to the other objects in the project.
  51. dhruv force-pushed on Oct 15, 2022
  52. dhruv commented at 4:15 am on October 15, 2022: contributor

    Latest push:

    • secp256k1_ellswift_create() does not need to be supplied auxrnd32 when the private key is unpredictable.
  53. dhruv force-pushed on Oct 21, 2022
  54. dhruv commented at 5:43 am on October 21, 2022: contributor

    Latest push:

    • Rebased
    • Brought in upstream changes with test vectors
  55. dhruv force-pushed on Nov 18, 2022
  56. dhruv commented at 5:18 am on November 18, 2022: contributor

    Latest push:

  57. dhruv force-pushed on Dec 15, 2022
  58. dhruv commented at 4:51 pm on December 15, 2022: contributor

    Latest push:

    • Rebased upstream changes
  59. dhruv force-pushed on Jan 12, 2023
  60. dhruv commented at 7:09 pm on January 12, 2023: contributor
    Rebased. Brought in latest from https://github.com/bitcoin-core/secp256k1/pull/1129
  61. DrahtBot added the label Needs rebase on Jan 13, 2023
  62. dhruv force-pushed on Jan 13, 2023
  63. dhruv commented at 11:44 pm on January 13, 2023: contributor
    Rebased.
  64. dhruv renamed this:
    BIP324: CPubKey encode/decode to elligator-swift
    BIP324: CKey encode/decode to elligator-swift
    on Jan 13, 2023
  65. DrahtBot removed the label Needs rebase on Jan 14, 2023
  66. in src/key.cpp:341 in 5b406499c2 outdated
    332@@ -332,6 +333,17 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
    333     return ret;
    334 }
    335 
    336+std::optional<EllSwiftPubKey> CKey::EllSwiftEncode() const
    337+{
    338+    EllSwiftPubKey encoded_pubkey;
    339+    if (!secp256k1_ellswift_create(secp256k1_context_sign,
    340+                                   reinterpret_cast<unsigned char*>(encoded_pubkey.data()),
    341+                                   keydata.data(), nullptr)) {
    


    sipa commented at 2:26 pm on January 14, 2023:

    This should probably pass in 32 bytes of randomness still. The algorithm should yield an encoding indistinguishable from random without it, but it’s certainly better to provide it if we can.

    In order to make fuzzing useful, the randomness would need to be passed in explicitly (e.g. as a const uint256& argument to CKey::EllSwiftEncode).


    dhruv commented at 6:10 am on January 17, 2023:
    Done.
  67. in src/test/key_tests.cpp:352 in 5b406499c2 outdated
    346@@ -344,4 +347,40 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
    347     }
    348 }
    349 
    350+CPubKey EllSwiftDecode(const EllSwiftPubKey& encoded_pubkey)
    351+{
    352+    auto secp256k1_context_verify = secp256k1_context_static;
    


    sipa commented at 2:28 pm on January 14, 2023:
    These first 3 lines are superfluous I think. The static context always exists, and an encoded_pubkey is a 64-byte array, it can only be 64 bytes.

    dhruv commented at 6:11 am on January 17, 2023:
    You’re right that was left over from older code where it was a vector instead of an array. Thanks for the catch. Fixed.
  68. in src/test/key_tests.cpp:374 in 5b406499c2 outdated
    369+    for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
    370+        CKey key = DecodeSecret(secret);
    371+        BOOST_CHECK(key.IsValid());
    372+
    373+        auto ellswift_encoded_pubkey = key.EllSwiftEncode();
    374+
    


    sipa commented at 2:30 pm on January 14, 2023:

    This probably needs a BOOST_CHECK(ellswift_encoded_pubkey.has_value());, otherwise you’d hit UB if somehow nullopt is returned.

    EDIT: unless the std::optional is dropped.


    dhruv commented at 6:11 am on January 17, 2023:
    dropped std::optional
  69. in src/test/fuzz/key.cpp:317 in 74b24f9be6 outdated
    312+    auto key_bytes = fdp.ConsumeBytes<uint8_t>(32);
    313+    key_bytes.resize(32);
    314+    CKey key;
    315+    key.Set(key_bytes.begin(), key_bytes.end(), fdp.ConsumeBool());
    316+
    317+    (void)key.EllSwiftEncode();
    


    sipa commented at 2:31 pm on January 14, 2023:
    This could also decode back, and test that the public keys correspond (if you move the EllSwiftDecode function to CPubKey, for example).

    dhruv commented at 6:12 am on January 17, 2023:
    Added this check, but I opted to decode locally in the fuzz test so as to not add code to CPubKey that would be used only for tests.
  70. in src/key.cpp:336 in 5b406499c2 outdated
    332@@ -332,6 +333,17 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
    333     return ret;
    334 }
    335 
    336+std::optional<EllSwiftPubKey> CKey::EllSwiftEncode() const
    


    sipa commented at 2:36 pm on January 14, 2023:
    No need to return an std::optional here. If the CKey is valid, the encoding will always succeed. You could e.g. assert(fValid); to require a valid CKey as object to operate on.

    dhruv commented at 6:13 am on January 17, 2023:
    Fixed
  71. dhruv force-pushed on Jan 17, 2023
  72. dhruv commented at 6:20 am on January 17, 2023: contributor

    Latest push:

    • Addressed review comments from @sipa
  73. DrahtBot added the label Needs rebase on Jan 28, 2023
  74. dhruv force-pushed on Feb 2, 2023
  75. dhruv commented at 6:26 am on February 2, 2023: contributor
    Rebased. Brought in changes from https://github.com/bitcoin-core/secp256k1/pull/1129.
  76. DrahtBot removed the label Needs rebase on Feb 2, 2023
  77. dhruv force-pushed on Mar 8, 2023
  78. dhruv commented at 3:27 pm on March 8, 2023: contributor
    Rebased. Brought in changes from https://github.com/bitcoin-core/secp256k1/pull/1129.
  79. DrahtBot added the label Needs rebase on Mar 12, 2023
  80. Squashed 'src/secp256k1/' changes from bdf39000b9..8034c67a48
    8034c67a48 Add doc/ellswift.md with ElligatorSwift explanation
    e90aa4e62e Add ellswift testing to CI
    131faedd8a Add ElligatorSwift ctime tests
    198a04c058 Add tests for ElligatorSwift
    9984bfe476 Add ElligatorSwift benchmarks
    f053da3ab7 Add ellswift module implementing ElligatorSwift
    76c64be237 Add functions to test if X coordinate is valid
    aff948fca2 Add benchmark for key generation
    5ed9314d6d Add exhaustive tests for ecmult_const_xonly
    b69fe88d5e Add x-only ecmult_const version for x=n/d
    427bc3cdcf Merge bitcoin-core/secp256k1#1236: Update comment for secp256k1_modinv32_inv256
    647f0a5cb1 Update comment for secp256k1_modinv32_inv256
    5658209459 Merge bitcoin-core/secp256k1#1228: release cleanup: bump version after 0.3.0
    28e63f7ea7 release cleanup: bump version after 0.3.0
    
    git-subtree-dir: src/secp256k1
    git-subtree-split: 8034c67a48dc1334bc74ee4ba239111a23d9789e
    963f9a5c61
  81. Merge commit '963f9a5c6159d985eb16b115a7d27027074827ed' into bip324-ellsq 1f0eca0651
  82. Encode CKey to ElligatorSwift representation 13423e6054
  83. Bench tests for CKey->EllSwift 697a23765e
  84. Fuzz tests for CKey->EllSwift ae4b695aac
  85. dhruv force-pushed on Mar 21, 2023
  86. dhruv commented at 4:02 am on March 21, 2023: contributor
    Rebased.
  87. DrahtBot removed the label Needs rebase on Mar 21, 2023
  88. DrahtBot added the label Needs rebase on Apr 15, 2023
  89. DrahtBot commented at 1:20 pm on April 15, 2023: contributor

    🐙 This pull request conflicts with the target branch and needs rebase.

  90. fanquake commented at 0:39 am on April 18, 2023: member
    Closing for now. See #27479.
  91. fanquake closed this on Apr 18, 2023

  92. achow101 referenced this in commit 679f825ba3 on Jun 26, 2023
  93. bitcoin locked this on Apr 17, 2024

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-09-28 22:12 UTC

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