From 01e06da4dedfb72fe1a866bd2117db3bef61c74a Mon Sep 17 00:00:00 2001 From: selsta Date: Thu, 25 Jun 2026 19:49:42 +0200 Subject: [PATCH] tests: add CLSAG fuzz tests Co-authored-by: Nym Seddon --- contrib/fuzz_testing/fuzz.sh | 6 +- tests/data/fuzz/clsag/clsag0 | 0 tests/data/fuzz/clsag/clsag1 | Bin 0 -> 417 bytes tests/data/fuzz/clsag_cout/clsag0 | 0 tests/data/fuzz/clsag_cout/clsag1 | 1 + tests/data/fuzz/clsag_message/clsag0 | 0 tests/data/fuzz/clsag_message/clsag1 | Bin 0 -> 32 bytes tests/data/fuzz/clsag_pubs/clsag0 | 0 tests/data/fuzz/clsag_pubs/clsag1 | Bin 0 -> 34 bytes tests/fuzz/CMakeLists.txt | 48 ++++++++++++++++ tests/fuzz/clsag.cpp | 52 +++++++++++++++++ tests/fuzz/clsag_cout.cpp | 50 +++++++++++++++++ tests/fuzz/clsag_init.h | 81 +++++++++++++++++++++++++++ tests/fuzz/clsag_message.cpp | 51 +++++++++++++++++ tests/fuzz/clsag_pubs.cpp | 52 +++++++++++++++++ 15 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 tests/data/fuzz/clsag/clsag0 create mode 100644 tests/data/fuzz/clsag/clsag1 create mode 100644 tests/data/fuzz/clsag_cout/clsag0 create mode 100644 tests/data/fuzz/clsag_cout/clsag1 create mode 100644 tests/data/fuzz/clsag_message/clsag0 create mode 100644 tests/data/fuzz/clsag_message/clsag1 create mode 100644 tests/data/fuzz/clsag_pubs/clsag0 create mode 100644 tests/data/fuzz/clsag_pubs/clsag1 create mode 100644 tests/fuzz/clsag.cpp create mode 100644 tests/fuzz/clsag_cout.cpp create mode 100644 tests/fuzz/clsag_init.h create mode 100644 tests/fuzz/clsag_message.cpp create mode 100644 tests/fuzz/clsag_pubs.cpp diff --git a/contrib/fuzz_testing/fuzz.sh b/contrib/fuzz_testing/fuzz.sh index 5c88c3727..065dcc381 100755 --- a/contrib/fuzz_testing/fuzz.sh +++ b/contrib/fuzz_testing/fuzz.sh @@ -10,12 +10,12 @@ fi type="$1" if test -z "$type" then - echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof" + echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof|utf8|clsag|clsag_cout|clsag_message|clsag_pubs" exit 1 fi case "$type" in - block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof|utf8) ;; - *) echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof|utf8"; exit 1 ;; + block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof|utf8|clsag|clsag_cout|clsag_message|clsag_pubs) ;; + *) echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof|utf8|clsag|clsag_cout|clsag_message|clsag_pubs"; exit 1 ;; esac if test -d "fuzz-out/$type" diff --git a/tests/data/fuzz/clsag/clsag0 b/tests/data/fuzz/clsag/clsag0 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fuzz/clsag/clsag1 b/tests/data/fuzz/clsag/clsag1 new file mode 100644 index 0000000000000000000000000000000000000000..36205eed58b1423af216ee707c7feb00d5d63fbc GIT binary patch literal 417 zcmV;S0bc$KPP=Y=>ESx$6K^2K^neityB4H8mUKQc0iRJ#$Z;zQ{+w!uqs)jo%UCwn z#x3TY{;k2fSf!0j-SPUAlY>kNcjUg{a7V7<2^vzhjh8V9v4ZsmrrG(mQsWQ!_SDb= z=Y|gX$fqJEv`9SGS8f&zs*7hd=ke_97Jh-fZO_^U!tTsirb~xtrwFkA zN7ubrkk&WLQA8O6jr91|ot(M!>-<^ z5i+|RfP!)(FTJfPwJlx79DE_8syj|(Ji`A=n4@G8}>a0b`7waleN*SQlg8UPcOj!0CMXs L*+|myibc(-h)>yX literal 0 HcmV?d00001 diff --git a/tests/data/fuzz/clsag_cout/clsag0 b/tests/data/fuzz/clsag_cout/clsag0 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fuzz/clsag_cout/clsag1 b/tests/data/fuzz/clsag_cout/clsag1 new file mode 100644 index 000000000..31cc17d65 --- /dev/null +++ b/tests/data/fuzz/clsag_cout/clsag1 @@ -0,0 +1 @@ +7kq>}`΄j@#]d| 5n \ No newline at end of file diff --git a/tests/data/fuzz/clsag_message/clsag0 b/tests/data/fuzz/clsag_message/clsag0 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fuzz/clsag_message/clsag1 b/tests/data/fuzz/clsag_message/clsag1 new file mode 100644 index 0000000000000000000000000000000000000000..9870828e3938f3276a5cd4a38d05b7281f0cd502 GIT binary patch literal 32 KcmZQ%zz+ZbKmY;& literal 0 HcmV?d00001 diff --git a/tests/data/fuzz/clsag_pubs/clsag0 b/tests/data/fuzz/clsag_pubs/clsag0 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/fuzz/clsag_pubs/clsag1 b/tests/data/fuzz/clsag_pubs/clsag1 new file mode 100644 index 0000000000000000000000000000000000000000..15515fe3f0824970899065699b7dc41139147e9c GIT binary patch literal 34 LcmZQza3lZ#hB62t literal 0 HcmV?d00001 diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 3b8ae9e7d..5d14c51cc 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -294,3 +294,51 @@ target_link_libraries(utf8_fuzz_tests ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES} $ENV{LIB_FUZZING_ENGINE}) + +monero_add_minimal_executable(clsag_fuzz_tests clsag.cpp clsag_init.h fuzzer.cpp) +target_link_libraries(clsag_fuzz_tests + PRIVATE + cryptonote_core + serialization + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES} + $ENV{LIB_FUZZING_ENGINE}) +set_property(TARGET clsag_fuzz_tests + PROPERTY + FOLDER "tests") + +monero_add_minimal_executable(clsag_cout_fuzz_tests clsag_cout.cpp clsag_init.h fuzzer.cpp) +target_link_libraries(clsag_cout_fuzz_tests + PRIVATE + cryptonote_core + serialization + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES} + $ENV{LIB_FUZZING_ENGINE}) +set_property(TARGET clsag_cout_fuzz_tests + PROPERTY + FOLDER "tests") + +monero_add_minimal_executable(clsag_message_fuzz_tests clsag_message.cpp clsag_init.h fuzzer.cpp) +target_link_libraries(clsag_message_fuzz_tests + PRIVATE + cryptonote_core + serialization + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES} + $ENV{LIB_FUZZING_ENGINE}) +set_property(TARGET clsag_message_fuzz_tests + PROPERTY + FOLDER "tests") + +monero_add_minimal_executable(clsag_pubs_fuzz_tests clsag_pubs.cpp clsag_init.h fuzzer.cpp) +target_link_libraries(clsag_pubs_fuzz_tests + PRIVATE + cryptonote_core + serialization + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES} + $ENV{LIB_FUZZING_ENGINE}) +set_property(TARGET clsag_pubs_fuzz_tests + PROPERTY + FOLDER "tests") diff --git a/tests/fuzz/clsag.cpp b/tests/fuzz/clsag.cpp new file mode 100644 index 000000000..825b4c243 --- /dev/null +++ b/tests/fuzz/clsag.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2017-2026, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "serialization/binary_utils.h" +#include "fuzzer.h" +#include "clsag_init.h" + +#include + +using namespace rct; + +BEGIN_INIT_SIMPLE_FUZZER() + clsag_init(); +END_INIT_SIMPLE_FUZZER() + +BEGIN_SIMPLE_FUZZER() + if (len > 4096) + return 0; + + // fuzz deserialization + clsag sig; + const std::string blob(reinterpret_cast(buf), len); + if (!serialization::parse_binary(blob, sig)) + return 0; + + verRctCLSAGSimple(message, sig, pubs, Cout); +END_SIMPLE_FUZZER() diff --git a/tests/fuzz/clsag_cout.cpp b/tests/fuzz/clsag_cout.cpp new file mode 100644 index 000000000..a5014566d --- /dev/null +++ b/tests/fuzz/clsag_cout.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2017-2026, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fuzzer.h" +#include "clsag_init.h" + +#include + +using namespace rct; + +static_assert(sizeof(key) == 32, "rct::key must be 32 bytes"); + +BEGIN_INIT_SIMPLE_FUZZER() + clsag_init(); +END_INIT_SIMPLE_FUZZER() + +BEGIN_SIMPLE_FUZZER() + if (len < sizeof(key)) + return 0; + + // fuzz Cout + key cout = Cout; + std::memcpy(&cout, buf, sizeof(key)); + verRctCLSAGSimple(message, clsag_s, pubs, cout); +END_SIMPLE_FUZZER() diff --git a/tests/fuzz/clsag_init.h b/tests/fuzz/clsag_init.h new file mode 100644 index 000000000..ab4fd6347 --- /dev/null +++ b/tests/fuzz/clsag_init.h @@ -0,0 +1,81 @@ +// Copyright (c) 2017-2026, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "cryptonote_basic/cryptonote_basic.h" +#include "misc_log_ex.h" +#include "ringct/rctSigs.h" + +using namespace crypto; +using namespace rct; + +static key message; +static ctkeyV pubs; +static key Cout; +static clsag clsag_s; + +inline static void clsag_init() { + message = identity(); + + const size_t N = 11; + const size_t idx = 5; + + pubs.clear(); + pubs.reserve(N); + + for (size_t i = 0; i < N; ++i) + { + key sk; + ctkey tmp; + + skpkGen(sk, tmp.dest); + skpkGen(sk, tmp.mask); + + pubs.push_back(tmp); + } + + // Set P[idx] + key p; + skpkGen(p, pubs[idx].dest); + + // Set C[idx] + key t = skGen(); + key u = skGen(); + addKeys2(pubs[idx].mask,t,u,H); + + // Set commitment offset + key t2 = skGen(); + addKeys2(Cout,t2,u,H); + + // Prepare generation inputs + ctkey insk; + insk.dest = p; + insk.mask = t; + + clsag_s = proveRctCLSAGSimple(message, pubs, insk, t2, Cout, idx, hw::get_device("default")); + CHECK_AND_ASSERT_THROW_MES(verRctCLSAGSimple(message, clsag_s, pubs, Cout), "Generated CLSAG does not verify"); +} diff --git a/tests/fuzz/clsag_message.cpp b/tests/fuzz/clsag_message.cpp new file mode 100644 index 000000000..044140e20 --- /dev/null +++ b/tests/fuzz/clsag_message.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2017-2026, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fuzzer.h" +#include "clsag_init.h" + +#include + +using namespace crypto; +using namespace rct; + +static_assert(sizeof(key) == 32, "rct::key must be 32 bytes"); + +BEGIN_INIT_SIMPLE_FUZZER() + clsag_init(); +END_INIT_SIMPLE_FUZZER() + +BEGIN_SIMPLE_FUZZER() + if (len < sizeof(key)) + return 0; + + // fuzz message + key fuzzed_message = message; + std::memcpy(&fuzzed_message, buf, sizeof(key)); + verRctCLSAGSimple(fuzzed_message, clsag_s, pubs, Cout); +END_SIMPLE_FUZZER() diff --git a/tests/fuzz/clsag_pubs.cpp b/tests/fuzz/clsag_pubs.cpp new file mode 100644 index 000000000..385ddc566 --- /dev/null +++ b/tests/fuzz/clsag_pubs.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2017-2026, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fuzzer.h" +#include "clsag_init.h" + +#include + +using namespace rct; + +static_assert(sizeof(key) == 32, "rct::key must be 32 bytes"); + +BEGIN_INIT_SIMPLE_FUZZER() + clsag_init(); +END_INIT_SIMPLE_FUZZER() + +BEGIN_SIMPLE_FUZZER() + if (len < sizeof(key) + 2) + return 0; + + ctkeyV fuzzed_pubs = pubs; + const size_t index = buf[0] % fuzzed_pubs.size(); + key& pub = (buf[1] & 1) ? fuzzed_pubs[index].mask : fuzzed_pubs[index].dest; + std::memcpy(&pub, buf + 2, sizeof(key)); + + verRctCLSAGSimple(message, clsag_s, fuzzed_pubs, Cout); +END_SIMPLE_FUZZER()