-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Make poly1305 support incremental computation + modernize #27993
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. |
96ad961
to
c9209ef
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
Verified that the poly1305 implementation introduced in 4abc846 matches poly1305-donna (used https://github.com/openbsd/src/blob/master/sys/crypto/poly1305.c as a reference, which is again based on Andrew Moon's implementation with minor adaptions). Still planning to verify the test vectors with another implementation, likely PyCryptodome.
This code is taken from poly1305-donna-32.h, poly1305-donna.h, poly1305-donna.c from https://github.com/floodyberry/poly1305-donna, commit e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781, with the following modifications: * Coding style (braces around one-line indented if/for loops). * Rename unsigned long (long) to uint32_t and uint64_t. * Rename poly1305_block_size to POLY1305_BLOCK_SIZE. * Adding noexcept to functions. * Merging poly1305_state_internal_t and poly1305_context types. * Merging code from multiple files. * Place all imported code in the poly1305_donna namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall. Verified the introduced test vectors (40de8ce) with the pyca/cryptography library, which uses OpenSSL in the background (tried with PyCryptodome first, but that didn't allow use of raw Poly1305 without a cipher algorithm). As expected, everything passes with this alternative implementation as well.
Python code
#!/usr/bin/env python3
from cryptography.hazmat.primitives.poly1305 import Poly1305
def test_poly1305(msg, key, tag):
p = Poly1305(bytes.fromhex(key))
p.update(bytes.fromhex(msg))
assert p.finalize() == bytes.fromhex(tag)
test_poly1305("8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a" +
"c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738" +
"b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da" +
"99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74" +
"e355a5",
"eea6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff880",
"f3ffc7703f9400e52a7dfb4b3d3305d9")
total_ctx = Poly1305(bytes.fromhex("01020304050607fffefdfcfbfaf9ffffffffffffffffffffffffffff00000000"))
for i in range(256):
key = bytes([i]*32)
msg = bytes([i]*i)
p = Poly1305(key)
p.update(msg)
tag = p.finalize()
total_ctx.update(tag)
assert total_ctx.finalize() == bytes.fromhex("64afe2e8d6ad7bbdd287f97c44623d39")
test_poly1305("000000000000000000000094000000000000b07c4300000000002c002600d500" +
"00000000000000000000000000bc58000000000000000000c9000000dd000000" +
"00000000000000d34c000000000000000000000000f9009100000000000000c2" +
"4b0000e900000000000000000000000000000000000e00000027000074000000" +
"0000000003000000000000f1000000000000dce2000000000000003900000000" +
"0000000000000000000000000000000000000000000000520000000000000000" +
"000000000000000000000000009500000000000000000000000000cf00826700" +
"000000a900000000000000000000000000000000000000000079000000000000" +
"0000de0000004c000000000033000000000000000000000000002800aa000000" +
"00003300860000e000000000",
"6e543496db3cf677592989891ab021f58390feb84fb419fbc7bb516a60bfa302",
"7ea80968354d40d9d790b45310caf7f3")
test_poly1305("0000005900000000c40000002f00000000000000000000000000000029690000" +
"0000e8000037000000000000000000000000000b000000000000000000000000" +
"000000000000000000000000001800006e0000000000a4000000000000000000" +
"00000000000000004d00000000000000b0000000000000000000005a00000000" +
"0000000000b7c300000000000000540000000000000000000000000a00000000" +
"00005b0000000000000000000000000000000000002d00e70000000000000000" +
"000000000000003400006800d700000000000000000000360000000000000000" +
"00eb000000000000000000000000000000000000000000000000000028000000" +
"37000000000000000000000000000000000000000000000000000000008f0000" +
"000000000000000000000000",
"f0b659a4f3143d8a1e1dacb9a409fe7e7cd501dfb58b16a2623046c5d337922a",
"0e410fa9d7a40ac582e77546be9a72bb")
Left some nits for removing the need for Make{Writable}ByteSpan
calls. I think they can also be applied to the TestPoly1305
function.
This also removes the old poly1305_auth interface, as it no longer serves any function. The new Poly1305 class based interface is more modern and safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 4e5c933
@MarcoFalke You may be interested in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, happy to leave comments, but I think it may be better to fix them in a follow-up, unless you really want to here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested ACK 4e5c933.
cross checked that this is consistent with poly1305-donna implementation. benchmarks look better compared to previous poly1305_auth
code too. (also found this blogpost which explains poly1305's design interesting!)
noticed this tiny difference in poly1305-donna's vs RFC 8439 r
- though it might also be some trick for later computation i guess.
- r before clamping: 85:d6:be:78:57:55:6d:33:7f:44:52:fe:42:d5:06:a8
- Clamped r as a number: 806d5400e52447c036d555408bed685
- chopping r into 5 pieces for r[0], r[1], r[2], r[3], r[4]
- can be written as: 806d5, 400e524, 47c036, d555408, bed685
- r in floodyberry's : 806d5, 1003949, 47c036, 3555502, bed685
- where 400e524 = 1003949 + "two zero bits" and d555408 = 3555502 + "two zero bits"
@stratospher There are two approaches for poly1305 implementations out there; one where the key (and the accumulated hash value) are represented using 32-bit limbs, and one where it's represented using 26-bit limbs (so in one |
@MarcoFalke Thanks for the comments; I think I'm going to create a separate PR with some further code refactoring related to this as well, outside of the critical path of #25361. |
ACK 4e5c933 Verified that this was consistent with poly1305-donna. |
…modernize 4e5c933 Switch all callers from poly1305_auth to Poly1305 class (Pieter Wuille) 8871f7d tests: add more Poly1305 test vectors (Pieter Wuille) 40e6c5b crypto: add Poly1305 class with std::byte Span interface (Pieter Wuille) 50269b3 crypto: switch poly1305 to incremental implementation (Pieter Wuille) Pull request description: Our current Poly1305 code (src/crypto/poly1305.*) only supports computing the entire tag in one go (the `poly1305_auth` function takes a key and message, and outputs the tag). However, the RFC8439 authenticated encryption (as used in BIP324, see bitcoin#27634) scheme makes use of Poly1305 in a way where the message consists of 3 different pieces: * The additionally authenticated data (AAD), padded to 16 bytes. * The ciphertext, padded to 16 bytes. * The length of the AAD and the length of the ciphertext, together another 16 bytes. Implementing RFC8439 using the existing `poly1305_auth` function requires creating a temporary copy with all these pieces of data concatenated just for the purpose of computing the tag (the approach used in bitcoin#25361). This PR replaces the poly1305 code with new code from https://github.com/floodyberry/poly1305-donna (with minor adjustments to make it match our coding style and use our utility functions, documented in the commit) which supports incremental operation, and then adds a C++ wrapper interface using std::byte Spans around it, and adds tests that incremental and all-at-once computation match. ACKs for top commit: achow101: ACK 4e5c933 theStack: ACK 4e5c933 stratospher: tested ACK 4e5c933. Tree-SHA512: df6e9a2a4a38a480f9e4360d3e3def5311673a727a4a85b008a084cf6843b260dc82cec7c73e1cecaaccbf10f3521a0ae7dba388b65d0b086770f7fbc5223e2a
1c7582e tests: add decryption test to bip324_tests (Pieter Wuille) 990f0f8 Add BIP324Cipher, encapsulating key agreement, derivation, and stream/AEAD ciphers (Pieter Wuille) c91cedf crypto: support split plaintext in ChaCha20Poly1305 Encrypt/Decrypt (Pieter Wuille) af2b44c bench: add benchmark for FSChaCha20Poly1305 (Pieter Wuille) aa8cee9 crypto: add FSChaCha20Poly1305, rekeying wrapper around ChaCha20Poly1305 (Pieter Wuille) 0fee267 crypto: add FSChaCha20, a rekeying wrapper around ChaCha20 (Pieter Wuille) 9ff0768 crypto: add the ChaCha20Poly1305 AEAD as specified in RFC8439 (Pieter Wuille) 9fd085a crypto: remove outdated variant of ChaCha20Poly1305 AEAD (Pieter Wuille) Pull request description: Depends on #27985 and #27993, based on and partially replaces #25361, part of #27634. Draft while dependencies are not merged. This adds implementations of: * The ChaCha20Poly1305 AEAD from [RFC8439 section 2.8](https://datatracker.ietf.org/doc/html/rfc8439#section-2.8), including test vectors. * The FSChaCha20 stream cipher as specified in [BIP324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#rekeying-wrappers-fschacha20poly1305-and-fschacha20), a rekeying wrapper around ChaCha20. * The FSChaCha20Poly1305 AEAD as specified in [BIP324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#rekeying-wrappers-fschacha20poly1305-and-fschacha20), a rekeying wrapper around ChaCha20Poly1305. * A BIP324Cipher class that encapsulates key agreement, key derivation, and stream ciphers and AEADs for [BIP324 packet encoding](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#overall-packet-encryption-and-decryption-pseudocode). The ChaCha20Poly1305 and FSChaCha20Poly1305 implementations are new, taking advance of the improvements in #27993. ACKs for top commit: jamesob: reACK 1c7582e theStack: ACK 1c7582e stratospher: tested ACK 1c7582e. Tree-SHA512: 06728b4b95b21c5b732ed08faf40e94d0583f9d86ff4db3b92dd519dcd9fbfa0f310bc66ef1e59c9e49dd844ba8c5ac06e2001762a804fb5aa97027816045a46
…tion & follow-ups 57cc136 crypto: make ChaCha20::SetKey wipe buffer (Pieter Wuille) da0ec62 tests: miscellaneous hex / std::byte improvements (Pieter Wuille) bdcbc85 fuzz: support std::byte in Consume{Fixed,Variable}LengthByteVector (Pieter Wuille) 7d1cd93 crypto: require key on ChaCha20 initialization (Pieter Wuille) 44c1176 random: simplify FastRandomContext::randbytes using fillrand (Pieter Wuille) 3da636e crypto: refactor ChaCha20 classes to use Span<std::byte> interface (Pieter Wuille) Pull request description: This modernizes the ChaCha20 and ChaCha20Aligned interfaces to be `Span<std::byte>` based, and other improvements. * Modifies all functions and constructors of `ChaCha20` and `ChaCha20Aligned` to be `Span<std::byte>` based (aligning them with `FSChaCha20`, `AEADChaCha20Poly1305`, and `FSChaCha20Poly1305`) * Remove default constructors, to make sure all call sites provide a key (suggested in bitcoin/bitcoin#26153 (comment)) * Wipe key material on rekey for security (suggested in bitcoin/bitcoin#26153 (comment)) * Use `HexStr` on byte vectors in tests (suggested in bitcoin/bitcoin#27993 (comment)) * Support `std::byte` vectors in `ConsumeRandomLengthByteVector` and `ConsumeFixedLengthByteVector`, and use it (suggested in bitcoin/bitcoin#27993 (comment)) * And a few more. While related, I don't see this as a necessary for BIP324. ACKs for top commit: stratospher: ACK 57cc136. theStack: re-ACK 57cc136 Tree-SHA512: 361da4ff003c8465a32eeac0983a8a6f047dbbf5b400168b409c8e3234e79d577fc854e0764389446585da3e12b964c94dd67fc0c9c1d1d092cec296121e05d4
…ollow-ups 57cc136 crypto: make ChaCha20::SetKey wipe buffer (Pieter Wuille) da0ec62 tests: miscellaneous hex / std::byte improvements (Pieter Wuille) bdcbc85 fuzz: support std::byte in Consume{Fixed,Variable}LengthByteVector (Pieter Wuille) 7d1cd93 crypto: require key on ChaCha20 initialization (Pieter Wuille) 44c1176 random: simplify FastRandomContext::randbytes using fillrand (Pieter Wuille) 3da636e crypto: refactor ChaCha20 classes to use Span<std::byte> interface (Pieter Wuille) Pull request description: This modernizes the ChaCha20 and ChaCha20Aligned interfaces to be `Span<std::byte>` based, and other improvements. * Modifies all functions and constructors of `ChaCha20` and `ChaCha20Aligned` to be `Span<std::byte>` based (aligning them with `FSChaCha20`, `AEADChaCha20Poly1305`, and `FSChaCha20Poly1305`) * Remove default constructors, to make sure all call sites provide a key (suggested in bitcoin#26153 (comment)) * Wipe key material on rekey for security (suggested in bitcoin#26153 (comment)) * Use `HexStr` on byte vectors in tests (suggested in bitcoin#27993 (comment)) * Support `std::byte` vectors in `ConsumeRandomLengthByteVector` and `ConsumeFixedLengthByteVector`, and use it (suggested in bitcoin#27993 (comment)) * And a few more. While related, I don't see this as a necessary for BIP324. ACKs for top commit: stratospher: ACK 57cc136. theStack: re-ACK 57cc136 Tree-SHA512: 361da4ff003c8465a32eeac0983a8a6f047dbbf5b400168b409c8e3234e79d577fc854e0764389446585da3e12b964c94dd67fc0c9c1d1d092cec296121e05d4
, bitcoin#28267, bitcoin#28374, bitcoin#28100 (p2p primitives) b60c493 merge bitcoin#28100: more Span<std::byte> modernization & follow-ups (Kittywhiskers Van Gogh) c2aa01c merge bitcoin#28374: python cryptography required for BIP 324 functional tests (Kittywhiskers Van Gogh) 7c5edf7 merge bitcoin#28267: BIP324 ciphersuite follow-up (Kittywhiskers Van Gogh) 1b1924e merge bitcoin#28008: BIP324 ciphersuite (Kittywhiskers Van Gogh) ff54219 merge bitcoin#27993: Make poly1305 support incremental computation + modernize (Kittywhiskers Van Gogh) d7482eb merge bitcoin#27985: Add support for RFC8439 variant of ChaCha20 (Kittywhiskers Van Gogh) Pull request description: ## Additional Information * Dependent on #5900 * Dependent on #5901 * Without modifications, tests introduced in [bitcoin#28008](bitcoin#28008) will fail due to salt comprising of a fixed string (`bitcoin_v2_shared_secret`) and network bytes ([source](https://github.com/sipa/bitcoin/blob/1c7582ead6e1119899922041c1af2b4169b0bc74/src/bip324.cpp#L39-L40)). Bitcoin uses [`{0xf9, 0xbe, 0xb4, 0xd9}`](https://github.com/sipa/bitcoin/blob/1c7582ead6e1119899922041c1af2b4169b0bc74/src/kernel/chainparams.cpp#L114-L117) for mainnet while Dash uses [`{0xbf, 0x0c, 0x6b, 0xbd}`](https://github.com/dashpay/dash/blob/37f43e4e56de0d510110a7f790df34ea77748dc9/src/chainparams.cpp#L238-L241). * The replacement parameters are generated by: * Cloning https://github.com/bitcoin/bips (as of this writing, at bitcoin/bips@b3701fa) * Editing `bip-0324/reference.py` * Changing `NETWORK_MAGIC` to Dash's network magic * Running `gen_test_vectors.py` to get a new `packet_encoding_test_vectors.csv` * Using [this python script](https://github.com/bitcoin/bitcoin/blob/1c7582ead6e1119899922041c1af2b4169b0bc74/src/test/bip324_tests.cpp#L174-L196) mentioned in a comment in `src/test/bip324_tests.cpp`, generate the values that will be used to replace the ones in `bip324_tests.cpp` (it will print to `stdout` so it's recommended to pipe it to a file) * Paste the new values over the old ones ## Breaking Changes None. Changes are restricted to BIP324 cryptosuite, tests and associated logic. ## Checklist: _Go over all the following points, and put an `x` in all the boxes that apply._ - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)** - [x] I have added or updated relevant unit/integration/functional/e2e tests **(note: N/A)** - [x] I have made corresponding changes to the documentation **(note: N/A)** - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ Top commit has no ACKs. Tree-SHA512: bb056de8588026adae63e78d56878274ff3934a439e2eae81606fa9c0a37dab432a129315bb9c1b754400b5c883bf460eea3a0c857a3be0816c8fbf55c479843
Our current Poly1305 code (src/crypto/poly1305.*) only supports computing the entire tag in one go (the
poly1305_auth
function takes a key and message, and outputs the tag). However, the RFC8439 authenticated encryption (as used in BIP324, see #27634) scheme makes use of Poly1305 in a way where the message consists of 3 different pieces:Implementing RFC8439 using the existing
poly1305_auth
function requires creating a temporary copy with all these pieces of data concatenated just for the purpose of computing the tag (the approach used in #25361).This PR replaces the poly1305 code with new code from https://github.com/floodyberry/poly1305-donna (with minor adjustments to make it match our coding style and use our utility functions, documented in the commit) which supports incremental operation, and then adds a C++ wrapper interface using std::byte Spans around it, and adds tests that incremental and all-at-once computation match.