Skip to content

Commit

Permalink
CLSAG C API
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffro256 committed Dec 8, 2024
1 parent 9866a0e commit c003fa3
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/ringct/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ target_link_libraries(ringct_basic
${EXTRA_LIBRARIES})

set(ringct_sources
clsag_c_api.cpp
rctSigs.cpp
)

set(ringct_headers)

set(ringct_private_headers
clsag_c_api.h
rctSigs.h
)

Expand Down
103 changes: 103 additions & 0 deletions src/ringct/clsag_c_api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) 2024, 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.

extern "C" {
#include "clsag_c_api.h"
}

#include "device/device.hpp"
#include "rctSigs.h"

#include <type_traits>

static rct::key key2rct(const monero_c_key *c_k)
{
static_assert(sizeof(monero_c_key) == sizeof(rct::key));

rct::key k;
memcpy(&k, c_k, sizeof(k));
return k;
}

static epee::span<const rct::key> pkey2span(const monero_c_key *p, const size_t len)
{
return {reinterpret_cast<const rct::key*>(p), len};
}

static hw::device &hwdev = hw::get_device("default");

struct monero_c_clsag
{
rct::clsag val;
};

extern "C" monero_c_clsag* monero_c_clsag_prove(const monero_c_key *m,
const monero_c_key *pubkeys,
const monero_c_key *privkey,
const monero_c_key *commits_to_zero,
const monero_c_key *commits,
const monero_c_key *pseudo_out,
const monero_c_key *blinding_factor_diff,
size_t index_in_ring,
size_t mixring_size)
{
return new monero_c_clsag{rct::CLSAG_Gen(key2rct(m),
pkey2span(pubkeys, mixring_size),
key2rct(privkey),
pkey2span(commits_to_zero, mixring_size),
key2rct(blinding_factor_diff),
pkey2span(commits, mixring_size),
key2rct(pseudo_out),
index_in_ring,
hwdev)};
}

extern "C" int monero_c_clsag_verify(const monero_c_key *m,
const monero_c_clsag *sig,
const monero_c_key *mixring_pubkeys,
const monero_c_key *mixring_commitments,
const monero_c_key *pseudo_out,
const size_t mixring_len)
{
rct::ctkeyV mixring(mixring_len);
for (size_t i = 0; i < mixring_len; ++i)
{
memcpy(&mixring[i].dest, mixring_pubkeys + i, sizeof(rct::key));
memcpy(&mixring[i].mask, mixring_commitments + i, sizeof(rct::key));
}

return rct::verRctCLSAGSimple(key2rct(m),
sig->val,
mixring,
key2rct(pseudo_out));
}

extern "C" void monero_c_clsag_destroy(monero_c_clsag* sig)
{
delete sig;
}
60 changes: 60 additions & 0 deletions src/ringct/clsag_c_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2024, 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.

#ifndef MONERO_CLSAG_C_API_H
#define MONERO_CLSAG_C_API_H

#include <stddef.h>

struct monero_c_key
{
unsigned char data[32];
};

struct monero_c_clsag;

monero_c_clsag* monero_c_clsag_prove(const monero_c_key *m,
const monero_c_key *pubkeys,
const monero_c_key *privkey,
const monero_c_key *commits_to_zero,
const monero_c_key *commits,
const monero_c_key *pseudo_out,
const monero_c_key *blinding_factor_diff,
size_t index_in_ring,
size_t mixring_size);

int monero_c_clsag_verify(const monero_c_key *m,
const monero_c_clsag *sig,
const monero_c_key *mixring_pubkeys,
const monero_c_key *mixring_commitments,
const monero_c_key *pseudo_out,
size_t mixring_len);

void monero_c_clsag_destroy(monero_c_clsag* clsag);

#endif
6 changes: 5 additions & 1 deletion src/ringct/rctSigs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ namespace rct {
// P[l] == p*G
// C[l] == z*G
// C[i] == C_nonzero[i] - C_offset (for hashing purposes) for all i
clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev) {
clsag CLSAG_Gen(const key &message, const epee::span<const key> P, const key & p, const epee::span<const key> C, const key & z, const epee::span<const key> C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev) {
clsag sig;
size_t n = P.size(); // ring size
CHECK_AND_ASSERT_THROW_MES(n == C.size(), "Signing and commitment key vector sizes must match!");
Expand Down Expand Up @@ -363,6 +363,10 @@ namespace rct {
return sig;
}

clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev) {
return CLSAG_Gen(message, epee::to_span(P), p, epee::to_span(C), z, epee::to_span(C_nonzero), C_offset, l, hwdev);
}

clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l) {
return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, hw::get_device("default"));
}
Expand Down
1 change: 1 addition & 0 deletions src/ringct/rctSigs.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace rct {
mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows, hw::device &hwdev);
bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows);

clsag CLSAG_Gen(const key &message, epee::span<const key> P, const key & p, epee::span<const key> C, const key & z, epee::span<const key> C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev);
clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev);
clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l);
clsag proveRctCLSAGSimple(const key &, const ctkeyV &, const ctkey &, const key &, const key &, unsigned int, hw::device &);
Expand Down
73 changes: 73 additions & 0 deletions tests/unit_tests/ringct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
#include <algorithm>
#include <sstream>

extern "C"
{
#include "ringct/clsag_c_api.h"
}
#include "ringct/rctTypes.h"
#include "ringct/rctSigs.h"
#include "ringct/rctOps.h"
Expand Down Expand Up @@ -1268,3 +1272,72 @@ TEST(ringct, aggregated)

ASSERT_TRUE(verRctSemanticsSimple(sp));
}

static monero_c_key rct2c(const key &k)
{
monero_c_key res;
memcpy(&res, &k, sizeof(res));
return res;
}

static key c2rct(const monero_c_key &c)
{
key res;
memcpy(&res, &c, sizeof(res));
return res;
}

TEST(ringct, monero_c_clsag_api)
{
static constexpr const size_t max_ring_size = 100;

std::vector<key> privkeys(max_ring_size);
for (auto &k : privkeys) k = skGen();

std::vector<key> blinders(max_ring_size);
for (auto &b : blinders) b = skGen();

std::vector<xmr_amount> amounts(max_ring_size);
for (auto &a : amounts) a = crypto::rand<xmr_amount>();

std::vector<monero_c_key> pubkeys(max_ring_size);
for (size_t i = 0; i < max_ring_size; ++i) pubkeys[i] = rct2c(scalarmultBase(privkeys[i]));

std::vector<monero_c_key> commitments(max_ring_size);
for (size_t i = 0; i < max_ring_size; ++i) commitments[i] = rct2c(commit(amounts[i], blinders[i]));

const monero_c_key msg = crypto::rand<monero_c_key>();

for (size_t ring_size = 1; ring_size <= max_ring_size; ++ring_size)
{
const size_t index_in_ring = crypto::rand_idx<size_t>(ring_size);
const monero_c_key true_privkey = rct2c(privkeys.at(index_in_ring));
const key &true_blinder = blinders.at(index_in_ring);
const xmr_amount true_amount = amounts.at(index_in_ring);

const monero_c_key blinding_factor_diff = rct2c(skGen());
key psuedo_blinding_factor;
sc_sub(psuedo_blinding_factor.bytes, true_blinder.bytes, blinding_factor_diff.data);
const monero_c_key psuedo_out = rct2c(commit(true_amount, psuedo_blinding_factor));

std::vector<monero_c_key> commits_to_zero(ring_size);
for (size_t i = 0; i < ring_size; ++i)
{
key tmp;
subKeys(tmp, c2rct(commitments.at(i)), c2rct(psuedo_out));
commits_to_zero[i] = rct2c(tmp);
}

monero_c_clsag* sig = monero_c_clsag_prove(&msg,
pubkeys.data(),
&true_privkey,
commits_to_zero.data(),
commitments.data(),
&psuedo_out,
&blinding_factor_diff,
index_in_ring,
ring_size);
ASSERT_TRUE(monero_c_clsag_verify(&msg, sig, pubkeys.data(), commitments.data(), &psuedo_out, ring_size));
monero_c_clsag_destroy(sig);
}
}

0 comments on commit c003fa3

Please sign in to comment.