Skip to content

Commit d415a81

Browse files
Merge remote-tracking branch 'origin/spats-integration' into spats_central_logic.
The main purpose being to resolve the "Bad Schnorr statement!" exception getting thrown from MintTransaction constructor, which this does indeed.
2 parents 9eae191 + ac056cf commit d415a81

9 files changed

+212
-221
lines changed

src/libspark/coin.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ std::size_t Coin::memoryRequired() {
205205
}
206206

207207
std::size_t Coin::memoryRequiredSpats() {
208-
secp_primitives::GroupElement groupElement;
209-
secp_primitives::Scalar scalar;
210-
return 1 + groupElement.memoryRequired() * 3 + 32 + AEAD_TAG_SIZE + sizeof(v) + scalar.memoryRequired() * 2;
208+
secp_primitives::GroupElement groupElement;
209+
secp_primitives::Scalar scalar;
210+
return 1 + groupElement.memoryRequired() * 3 + 32 + AEAD_TAG_SIZE + sizeof(v) + scalar.memoryRequired() * 2;
211211
}
212212

213213
bool Coin::operator==(const Coin& other) const {

src/libspark/coin.h

+8-8
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ const char COIN_TYPE_MINT_V2 = 2;
1919
const char COIN_TYPE_SPEND_V2 = 3;
2020

2121
struct IdentifiedCoinData {
22-
uint64_t i; // diversifier
23-
std::vector<unsigned char> d; // encrypted diversifier
24-
uint64_t v; // value
25-
Scalar k; // nonce
26-
std::string memo; // memo
27-
Scalar a = Scalar(uint64_t(0)); // asset type
28-
Scalar iota = Scalar(uint64_t(0)); // identifier
22+
uint64_t i; // diversifier
23+
std::vector<unsigned char> d; // encrypted diversifier
24+
uint64_t v; // value
25+
Scalar k; // nonce
26+
std::string memo; // memo
27+
Scalar a = Scalar(uint64_t(0)); // asset type
28+
Scalar iota = Scalar(uint64_t(0)); // identifier
2929
};
3030

3131
struct RecoveredCoinData {
@@ -97,7 +97,7 @@ class Coin {
9797
RecoveredCoinData recover(const FullViewKey& full_view_key, const IdentifiedCoinData& data);
9898

9999
static std::size_t memoryRequired();
100-
static std::size_t memoryRequiredSpats();
100+
static std::size_t memoryRequiredSpats();
101101

102102
bool operator==(const Coin& other) const;
103103
bool operator!=(const Coin& other) const;

src/libspark/mint_transaction.cpp

+25-25
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ MintTransaction::MintTransaction(const Params* params) {
77
}
88

99
MintTransaction::MintTransaction(
10-
const Params* params,
11-
const std::vector<MintedCoinData>& outputs,
12-
const std::vector<unsigned char>& serial_context,
10+
const Params* params,
11+
const std::vector<MintedCoinData>& outputs,
12+
const std::vector<unsigned char>& serial_context,
1313
bool generate
1414
) {
1515
// Important note: This construction assumes that the public coin values are correct according to higher-level consensus rules!
16-
// Important note: For pool transition transactions, the serial context should contain unique references to all base-layer spent assets, in order to ensure the resulting serial commitment is bound to this transaction
16+
// Important note: For pool transition transactions, the serial context should contain unique references to all base-layer spent assets, in order to ensure the resulting serial commitment is bound to this transaction
1717

18-
this->params = params;
19-
Schnorr schnorr(this->params->get_H());
18+
this->params = params;
19+
Schnorr schnorr(this->params->get_H());
2020

21-
std::vector<GroupElement> value_statement;
22-
std::vector<Scalar> value_witness;
21+
std::vector<GroupElement> value_statement;
22+
std::vector<Scalar> value_witness;
2323

24-
for (std::size_t j = 0; j < outputs.size(); j++) {
24+
for (std::size_t j = 0; j < outputs.size(); j++) {
2525
if (generate) {
2626
MintedCoinData output = outputs[j];
2727

@@ -41,7 +41,7 @@ MintTransaction::MintTransaction(
4141
));
4242

4343
// Prepare the value proof
44-
value_statement.emplace_back(this->coins[j].C + this->params->get_G().inverse()*Scalar(this->coins[j].v));
44+
value_statement.emplace_back(this->coins[j].C + this->params->get_E().inverse() * this->coins[j].a + this->params->get_F().inverse() * this->coins[j].iota + this->params->get_G().inverse()*Scalar(this->coins[j].v));
4545
value_witness.emplace_back(SparkUtils::hash_val(k));
4646
} else {
4747
Coin coin(params);
@@ -52,28 +52,28 @@ MintTransaction::MintTransaction(
5252
coin.v = 0;
5353
this->coins.emplace_back(coin);
5454
}
55-
}
55+
}
5656

57-
// Complete the value proof
57+
// Complete the value proof
5858
if (generate)
59-
schnorr.prove(value_witness, value_statement, this->value_proof);
59+
schnorr.prove(value_witness, value_statement, this->value_proof);
6060
else
6161
value_proof = SchnorrProof();
6262
}
6363

6464
bool MintTransaction::verify() {
65-
// Verify the value proof
66-
Schnorr schnorr(this->params->get_H());
67-
std::vector<GroupElement> value_statement;
68-
69-
for (std::size_t j = 0; j < this->coins.size(); j++) {
70-
value_statement.emplace_back(this->coins[j].C
71-
+ this->params->get_E().inverse() * this->coins[j].a
72-
+ this->params->get_F().inverse() * this->coins[j].iota
73-
+ this->params->get_G().inverse()*Scalar(this->coins[j].v));
74-
}
75-
76-
return schnorr.verify(value_statement, this->value_proof);
65+
// Verify the value proof
66+
Schnorr schnorr(this->params->get_H());
67+
std::vector<GroupElement> value_statement;
68+
69+
for (std::size_t j = 0; j < this->coins.size(); j++) {
70+
value_statement.emplace_back(this->coins[j].C
71+
+ this->params->get_E().inverse() * this->coins[j].a
72+
+ this->params->get_F().inverse() * this->coins[j].iota
73+
+ this->params->get_G().inverse()*Scalar(this->coins[j].v));
74+
}
75+
76+
return schnorr.verify(value_statement, this->value_proof);
7777
}
7878

7979
std::vector<CDataStream> MintTransaction::getMintedCoinsSerialized() {

src/libspark/spend_transaction.cpp

+68-68
Original file line numberDiff line numberDiff line change
@@ -53,60 +53,60 @@ SpendTransaction::SpendTransaction(
5353
this->params->get_m_grootle()
5454
);
5555
for (std::size_t u = 0; u < w; u++) {
56-
// Parse out cover set data for this spend
57-
uint64_t set_id = inputs[u].cover_set_id;
58-
this->cover_set_ids.emplace_back(set_id);
59-
if (cover_set_data.count(set_id) == 0 || cover_sets.count(set_id) == 0)
60-
throw std::invalid_argument("Required set is not passed");
61-
62-
const auto& cover_set = cover_sets.at(set_id);
63-
std::size_t set_size = cover_set.size();
64-
if (set_size > N)
65-
throw std::invalid_argument("Wrong set size");
66-
67-
std::vector<GroupElement> S, C;
68-
S.reserve(set_size);
69-
C.reserve(set_size);
70-
for (std::size_t i = 0; i < set_size; i++) {
71-
S.emplace_back(cover_set[i].S);
72-
C.emplace_back(cover_set[i].C);
73-
}
74-
75-
// Serial commitment offset
76-
this->S1.emplace_back(
77-
this->params->get_F()*inputs[u].s
78-
+ this->params->get_H().inverse()*SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D())
79-
+ full_view_key.get_D()
80-
);
81-
82-
// Value commitment offset
83-
this->C1.emplace_back(
84-
this->params->get_G()*Scalar(inputs[u].v)
85-
+ this->params->get_H()*SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D())
86-
);
87-
88-
// Tags
89-
this->T.emplace_back(inputs[u].T);
90-
91-
// Grootle proof
92-
this->grootle_proofs.emplace_back();
93-
std::size_t l = inputs[u].index;
94-
grootle.prove(
95-
l,
96-
SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()),
97-
S,
98-
this->S1.back(),
99-
SparkUtils::hash_val(inputs[u].k) - SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()),
100-
C,
101-
this->C1.back(),
102-
this->cover_set_representations[set_id],
103-
this->grootle_proofs.back()
104-
);
105-
106-
// Chaum data
107-
chaum_x.emplace_back(inputs[u].s);
108-
chaum_y.emplace_back(spend_key.get_r());
109-
chaum_z.emplace_back(SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()).negate());
56+
// Parse out cover set data for this spend
57+
uint64_t set_id = inputs[u].cover_set_id;
58+
this->cover_set_ids.emplace_back(set_id);
59+
if (cover_set_data.count(set_id) == 0 || cover_sets.count(set_id) == 0)
60+
throw std::invalid_argument("Required set is not passed");
61+
62+
const auto& cover_set = cover_sets.at(set_id);
63+
std::size_t set_size = cover_set.size();
64+
if (set_size > N)
65+
throw std::invalid_argument("Wrong set size");
66+
67+
std::vector<GroupElement> S, C;
68+
S.reserve(set_size);
69+
C.reserve(set_size);
70+
for (std::size_t i = 0; i < set_size; i++) {
71+
S.emplace_back(cover_set[i].S);
72+
C.emplace_back(cover_set[i].C);
73+
}
74+
75+
// Serial commitment offset
76+
this->S1.emplace_back(
77+
this->params->get_F()*inputs[u].s
78+
+ this->params->get_H().inverse()*SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D())
79+
+ full_view_key.get_D()
80+
);
81+
82+
// Value commitment offset
83+
this->C1.emplace_back(
84+
this->params->get_G()*Scalar(inputs[u].v)
85+
+ this->params->get_H()*SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D())
86+
);
87+
88+
// Tags
89+
this->T.emplace_back(inputs[u].T);
90+
91+
// Grootle proof
92+
this->grootle_proofs.emplace_back();
93+
std::size_t l = inputs[u].index;
94+
grootle.prove(
95+
l,
96+
SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()),
97+
S,
98+
this->S1.back(),
99+
SparkUtils::hash_val(inputs[u].k) - SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()),
100+
C,
101+
this->C1.back(),
102+
this->cover_set_representations[set_id],
103+
this->grootle_proofs.back()
104+
);
105+
106+
// Chaum data
107+
chaum_x.emplace_back(inputs[u].s);
108+
chaum_y.emplace_back(spend_key.get_r());
109+
chaum_z.emplace_back(SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()).negate());
110110
}
111111

112112
// Generate output coins and prepare range proof vectors
@@ -413,13 +413,13 @@ bool SpendTransaction::verify(
413413
//
414414
// Note that transparent components of the transaction are bound into `cover_set_representation`, so they don't appear separately.
415415
std::vector<unsigned char> SpendTransaction::hash_bind_inner(
416-
const std::map<uint64_t, std::vector<unsigned char>>& cover_set_representations,
417-
const std::vector<GroupElement>& S1,
418-
const std::vector<GroupElement>& C1,
419-
const std::vector<GroupElement>& T,
420-
const std::vector<GrootleProof>& grootle_proofs,
421-
const SchnorrProof& balance_proof,
422-
const BPPlusProof& range_proof
416+
const std::map<uint64_t, std::vector<unsigned char>>& cover_set_representations,
417+
const std::vector<GroupElement>& S1,
418+
const std::vector<GroupElement>& C1,
419+
const std::vector<GroupElement>& T,
420+
const std::vector<GrootleProof>& grootle_proofs,
421+
const SchnorrProof& balance_proof,
422+
const BPPlusProof& range_proof
423423
) {
424424
Hash hash(LABEL_HASH_BIND_INNER);
425425
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@@ -429,7 +429,7 @@ std::vector<unsigned char> SpendTransaction::hash_bind_inner(
429429
stream << T;
430430
stream << grootle_proofs;
431431
stream << balance_proof;
432-
stream << range_proof;
432+
stream << range_proof;
433433
hash.include(stream);
434434

435435
return hash.finalize();
@@ -438,16 +438,16 @@ std::vector<unsigned char> SpendTransaction::hash_bind_inner(
438438
// Hash-to-scalar function H_bind
439439
// This function must accept pre-hashed data from `H_bind_inner` intended to correspond to the signing operation
440440
Scalar SpendTransaction::hash_bind(
441-
const std::vector<unsigned char> hash_bind_inner,
441+
const std::vector<unsigned char> hash_bind_inner,
442442
const std::vector<Coin>& out_coins,
443443
const uint64_t f_
444444
) {
445-
Hash hash(LABEL_HASH_BIND);
445+
Hash hash(LABEL_HASH_BIND);
446446
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
447-
stream << hash_bind_inner,
448-
stream << out_coins;
449-
stream << f_;
450-
hash.include(stream);
447+
stream << hash_bind_inner,
448+
stream << out_coins;
449+
stream << f_;
450+
hash.include(stream);
451451

452452
return hash.finalize_scalar();
453453
}

0 commit comments

Comments
 (0)