Skip to content
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

Ownership proof #2

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ echo Building Spark Tests
g++ tests/spark_test.cpp src/*.cpp bitcoin/*.cpp bitcoin/support/*.cpp bitcoin/crypto/*.cpp -g -Isecp256k1/include secp256k1/.libs/libsecp256k1.a -lssl -lcrypto -lpthread -lboost_unit_test_framework -std=c++17 -o $1/spark_tests
echo Building Address Tests
g++ tests/address_test.cpp src/*.cpp bitcoin/*.cpp bitcoin/support/*.cpp bitcoin/crypto/*.cpp -g -Isecp256k1/include secp256k1/.libs/libsecp256k1.a -lssl -lcrypto -lpthread -lboost_unit_test_framework -std=c++17 -o $1/address_tests
echo Building Ownership Tests
g++ tests/ownership_test.cpp src/*.cpp bitcoin/*.cpp bitcoin/support/*.cpp bitcoin/crypto/*.cpp -g -Isecp256k1/include secp256k1/.libs/libsecp256k1.a -lssl -lcrypto -lpthread -lboost_unit_test_framework -std=c++17 -o $1/ownership_tests
echo Building Spark Coin Tests
g++ tests/coin_test.cpp src/*.cpp bitcoin/*.cpp bitcoin/support/*.cpp bitcoin/crypto/*.cpp -g -Isecp256k1/include secp256k1/.libs/libsecp256k1.a -lssl -lcrypto -lpthread -lboost_unit_test_framework -std=c++17 -o $1/spark_coin_tests
echo Building Spark Aead Tests
Expand Down
2 changes: 2 additions & 0 deletions run_all_tests
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ echo Running Spark Tests
./$1/spark_tests
echo Running Address Tests
./$1/address_tests
echo Running Ownership Tests
./$1/ownership_tests
echo Running Aead Tests
./$1/spark_aead_tests
echo Challenge Bpplus Tests
Expand Down
65 changes: 65 additions & 0 deletions src/keys.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "keys.h"
#include "../bitcoin/hash.h"
#include "transcript.h"

namespace spark {

Expand Down Expand Up @@ -243,4 +244,68 @@ unsigned char Address::decode(const std::string& str) {
return network;
}

Scalar Address::challenge(const Scalar& m, const GroupElement& A, const GroupElement& H) const {
Transcript transcript(LABEL_TRANSCRIPT_OWNERSHIP);
transcript.add("G", this->params->get_G());
transcript.add("F", this->params->get_F());
transcript.add("H", H);
transcript.add("A", A);
transcript.add("m", m);
transcript.add("d", this->d);
transcript.add("Q1", this->Q1);
transcript.add("Q2", this->Q2);

return transcript.challenge("c");
}

void Address::prove_own(const Scalar& m,
const SpendKey& spend_key,
const IncomingViewKey& incomingViewKey,
OwnershipProof& proof) const {
Scalar a, b, c;
a.randomize();
b.randomize();
c.randomize();

GroupElement H = SparkUtils::hash_div(this->d);
proof.A = H * a + this->params->get_G() * b + this->params->get_F() * c;

if (proof.A.isInfinity()) {
throw std::invalid_argument("Bad Proof construction!");
}

Scalar x = challenge(m, proof.A, H);

if (x.isZero()) {
throw std::invalid_argument("Unexpected challenge!");
}

Scalar x_sqr = x.square();

uint64_t i = incomingViewKey.get_diversifier(this->d);
proof.t1 = a + x * spend_key.get_s1();
proof.t2 = b + x_sqr * spend_key.get_r();
proof.t3 = c + x_sqr * (SparkUtils::hash_Q2(spend_key.get_s1(), i) + spend_key.get_s2());
}

bool Address::verify_own(const Scalar& m,
OwnershipProof& proof) const {
if (proof.A.isInfinity()) {
throw std::invalid_argument("Bad Ownership Proof!");
}

GroupElement H = SparkUtils::hash_div(this->d);
Scalar x = challenge(m, proof.A, H);
if (x.isZero()) {
throw std::invalid_argument("Unexpected challenge!");
}

Scalar x_sqr = x.square();

GroupElement left = proof.A + this->Q1 * x + this->Q2 * x_sqr;
GroupElement right = H * proof.t1 + this->params->get_G() * proof.t2 + this->params->get_F() * proof.t3;

return left == right;
}

}
11 changes: 11 additions & 0 deletions src/keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "f4grumble.h"
#include "params.h"
#include "util.h"
#include "../bitcoin/uint256.h"
#include "ownership_proof.h"

namespace spark {

Expand Down Expand Up @@ -82,6 +84,15 @@ class Address {
std::string encode(const unsigned char network) const;
unsigned char decode(const std::string& str);

Scalar challenge(const Scalar& m, const GroupElement& A, const GroupElement& H) const;
void prove_own(const Scalar& m,
const SpendKey& spend_key,
const IncomingViewKey& incomingViewKey,
OwnershipProof& proof) const;

bool verify_own(const Scalar& m,
OwnershipProof& proof) const;

private:
const Params* params;
std::vector<unsigned char> d;
Expand Down
31 changes: 31 additions & 0 deletions src/ownership_proof.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef FIRO_LIBSPARK_OWNERSHIP_PROOF_H
#define FIRO_LIBSPARK_OWNERSHIP_PROOF_H

#include "params.h"

namespace spark {

class OwnershipProof{
public:
inline std::size_t memoryRequired() const {
return Scalar::memoryRequired() * 3 + GroupElement::memoryRequired();
}

ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(A);
READWRITE(t1);
READWRITE(t2);
READWRITE(t3);
}

public:
GroupElement A;
Scalar t1;
Scalar t2;
Scalar t3;
};
}

#endif
1 change: 1 addition & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const std::string LABEL_TRANSCRIPT_BPPLUS = "BULLETPROOF_PLUS_V1";
const std::string LABEL_TRANSCRIPT_CHAUM = "CHAUM_V1";
const std::string LABEL_TRANSCRIPT_GROOTLE = "GROOTLE_V1";
const std::string LABEL_TRANSCRIPT_SCHNORR = "SCHNORR_V1";
const std::string LABEL_TRANSCRIPT_OWNERSHIP = "OWNERSHIP_V1";

// Generator labels
const std::string LABEL_GENERATOR_F = "F";
Expand Down
114 changes: 114 additions & 0 deletions tests/ownership_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "../src/keys.h"

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

namespace spark {

class SparkTest {};
BOOST_FIXTURE_TEST_SUITE(spark_address_ownership_tests, SparkTest)

BOOST_AUTO_TEST_CASE(serialization)
{
Scalar m;
m.randomize();

OwnershipProof proof;

const Params* params;
params = Params::get_test();

// Generate keys
SpendKey spend_key(params);
FullViewKey full_view_key(spend_key);
IncomingViewKey incoming_view_key(full_view_key);

// Generate address
const uint64_t i = 12345;
Address address(incoming_view_key, i);
address.prove_own(m, spend_key, incoming_view_key, proof);

CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION);
serialized << proof;

OwnershipProof deserialized;
serialized >> deserialized;

BOOST_CHECK(proof.A == deserialized.A);
BOOST_CHECK(proof.t1 == deserialized.t1);
BOOST_CHECK(proof.t2 == deserialized.t2);
BOOST_CHECK(proof.t3 == deserialized.t3);

}

BOOST_AUTO_TEST_CASE(completeness)
{
Scalar m;
m.randomize();

OwnershipProof proof;

const Params* params;
params = Params::get_test();

// Generate keys
SpendKey spend_key(params);
FullViewKey full_view_key(spend_key);
IncomingViewKey incoming_view_key(full_view_key);

// Generate address
const uint64_t i = 12345;
Address address(incoming_view_key, i);
address.prove_own(m, spend_key, incoming_view_key, proof);

CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION);
serialized << proof;

OwnershipProof deserialized;
serialized >> deserialized;

BOOST_CHECK(address.verify_own(m, deserialized));
}

BOOST_AUTO_TEST_CASE(bad_proofs)
{
Scalar m;
m.randomize();

OwnershipProof proof;

const Params* params;
params = Params::get_test();

// Generate keys
SpendKey spend_key(params);
FullViewKey full_view_key(spend_key);
IncomingViewKey incoming_view_key(full_view_key);

// Generate address
const uint64_t i = 12345;
Address address(incoming_view_key, i);
address.prove_own(m, spend_key, incoming_view_key, proof);

OwnershipProof evil_proof1 = proof;
evil_proof1.A.randomize();
BOOST_CHECK(!address.verify_own(m, evil_proof1));

OwnershipProof evil_proof2 = proof;
evil_proof2.t1.randomize();
BOOST_CHECK(!address.verify_own(m, evil_proof2));

OwnershipProof evil_proof3 = proof;
evil_proof3.t2.randomize();
BOOST_CHECK(!address.verify_own(m, evil_proof3));

OwnershipProof evil_proof4 = proof;
evil_proof4.t3.randomize();
BOOST_CHECK(!address.verify_own(m, evil_proof4));
}

BOOST_AUTO_TEST_SUITE_END()

}