Skip to content

Commit 8b8256d

Browse files
committed
Add ConfidentialCommitment-based types
1 parent d0322f7 commit 8b8256d

File tree

3 files changed

+260
-0
lines changed

3 files changed

+260
-0
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ libbitcoin_consensus_a_SOURCES = \
373373
prevector.h \
374374
primitives/block.cpp \
375375
primitives/block.h \
376+
primitives/confidential.cpp \
377+
primitives/confidential.h \
376378
primitives/txwitness.cpp \
377379
primitives/txwitness.h \
378380
primitives/transaction.cpp \

src/primitives/confidential.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
#include <primitives/confidential.h>
3+
4+
#include <tinyformat.h>
5+
6+
void CConfidentialAsset::SetToAsset(const CAsset& asset)
7+
{
8+
vchCommitment.clear();
9+
vchCommitment.reserve(nExplicitSize);
10+
vchCommitment.push_back(1);
11+
vchCommitment.insert(vchCommitment.end(), asset.begin(), asset.end());
12+
}
13+
14+
void CConfidentialValue::SetToAmount(const CAmount amount)
15+
{
16+
vchCommitment.resize(nExplicitSize);
17+
vchCommitment[0] = 1;
18+
WriteBE64(&vchCommitment[1], amount);
19+
}
20+
21+
std::string CAssetIssuance::ToString() const
22+
{
23+
std::string str;
24+
str += "CAssetIssuance(";
25+
str += assetBlindingNonce.ToString();
26+
str += ", ";
27+
str += assetEntropy.ToString();
28+
if (!nAmount.IsNull())
29+
str += strprintf(", amount=%s", (nAmount.IsExplicit() ? strprintf("%d.%08d", nAmount.GetAmount() / COIN, nAmount.GetAmount() % COIN) : std::string("CONFIDENTIAL")));
30+
if (!nInflationKeys.IsNull())
31+
str += strprintf(", inflationkeys=%s", (nInflationKeys.IsExplicit() ? strprintf("%d.%08d", nInflationKeys.GetAmount() / COIN, nInflationKeys.GetAmount() % COIN) : std::string("CONFIDENTIAL")));
32+
str += ")";
33+
return str;
34+
}

src/primitives/confidential.h

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
2+
#ifndef BITCOIN_PRIMITIVES_CONFIDENTIAL_H
3+
#define BITCOIN_PRIMITIVES_CONFIDENTIAL_H
4+
5+
#include <amount.h>
6+
#include <asset.h>
7+
#include <script/script.h>
8+
#include <serialize.h>
9+
#include <span.h>
10+
#include <uint256.h>
11+
#include <utilstrencodings.h>
12+
13+
extern bool g_con_elementswitness;
14+
15+
/**
16+
* Confidential assets, values, and nonces all share enough code in common
17+
* that it makes sense to define a common abstract base class. */
18+
template<size_t ExplicitSize, unsigned char PrefixA, unsigned char PrefixB>
19+
class CConfidentialCommitment
20+
{
21+
public:
22+
static const size_t nExplicitSize = ExplicitSize;
23+
static const size_t nCommittedSize = 33;
24+
25+
std::vector<unsigned char> vchCommitment;
26+
27+
CConfidentialCommitment() { SetNull(); }
28+
29+
ADD_SERIALIZE_METHODS;
30+
31+
template <typename Stream, typename Operation>
32+
inline void SerializationOp(Stream& s, Operation ser_action) {
33+
unsigned char version = vchCommitment.empty()? 0: vchCommitment[0];
34+
READWRITE(version);
35+
if (ser_action.ForRead()) {
36+
switch (version) {
37+
/* Null */
38+
case 0:
39+
vchCommitment.clear();
40+
return;
41+
/* Explicit value */
42+
case 1:
43+
vchCommitment.resize(nExplicitSize);
44+
break;
45+
/* Confidential commitment */
46+
case PrefixA:
47+
case PrefixB:
48+
vchCommitment.resize(nCommittedSize);
49+
break;
50+
/* Invalid serialization! */
51+
default:
52+
throw std::ios_base::failure("Unrecognized serialization prefix");
53+
}
54+
vchCommitment[0] = version;
55+
}
56+
if (vchCommitment.size() > 1) {
57+
READWRITE(REF(Span<unsigned char>(vchCommitment.data() + 1, vchCommitment.size()-1)));
58+
}
59+
}
60+
61+
/* Null is the default state when no explicit asset or confidential
62+
* asset commitment has been set. */
63+
bool IsNull() const { return vchCommitment.empty(); }
64+
void SetNull() { vchCommitment.clear(); }
65+
66+
bool IsExplicit() const
67+
{
68+
return vchCommitment.size()==nExplicitSize && vchCommitment[0]==1;
69+
}
70+
71+
bool IsCommitment() const
72+
{
73+
return vchCommitment.size()==nCommittedSize && (vchCommitment[0]==PrefixA || vchCommitment[0]==PrefixB);
74+
}
75+
76+
bool IsValid() const
77+
{
78+
return IsNull() || IsExplicit() || IsCommitment();
79+
}
80+
81+
std::string GetHex() const { return HexStr(vchCommitment); }
82+
83+
friend bool operator==(const CConfidentialCommitment& a, const CConfidentialCommitment& b)
84+
{
85+
return a.vchCommitment == b.vchCommitment;
86+
}
87+
88+
friend bool operator!=(const CConfidentialCommitment& a, const CConfidentialCommitment& b)
89+
{
90+
return !(a == b);
91+
}
92+
};
93+
94+
/** A commitment to a blinded asset, or an explicit asset NUMS identifier */
95+
class CConfidentialAsset : public CConfidentialCommitment<33, 10, 11>
96+
{
97+
public:
98+
CConfidentialAsset() {
99+
SetNull();
100+
}
101+
CConfidentialAsset(CAsset asset) { SetToAsset(asset); }
102+
103+
void SetNull() {
104+
vchCommitment.clear();
105+
106+
// Set to dummy asset when not doing CA.
107+
if (!g_con_elementswitness) {
108+
SetToAsset(CAsset());
109+
}
110+
}
111+
112+
/* An explicit asset identifier is a 256-bit nothing-up-my-sleeve number
113+
* that used as auxiliary input to the Pedersen commitment setup to create
114+
* a generator which acts as the asset tag. */
115+
const CAsset& GetAsset() const
116+
{
117+
assert(IsExplicit());
118+
return *reinterpret_cast<const CAsset*>(&vchCommitment[1]);
119+
}
120+
void SetToAsset(const CAsset& asset);
121+
122+
};
123+
124+
/** A 33-byte commitment to a confidential value, or a 64-bit explicit value. */
125+
class CConfidentialValue : public CConfidentialCommitment<9, 8, 9>
126+
{
127+
public:
128+
CConfidentialValue() { SetNull(); }
129+
CConfidentialValue(CAmount nAmount) { SetToAmount(nAmount); }
130+
131+
/* An explicit value is called an amount. The first byte indicates it is
132+
* an explicit value, and the remaining 8 bytes is the value serialized as
133+
* a 64-bit big-endian integer. */
134+
CAmount GetAmount() const
135+
{
136+
if (!g_con_elementswitness && IsNull()) {
137+
return -1;
138+
}
139+
140+
assert(IsExplicit());;
141+
return ReadBE64(&vchCommitment[1]);
142+
}
143+
void SetToAmount(CAmount nAmount);
144+
};
145+
146+
/**
147+
* A 33-byte data field that typically is used to convey to the
148+
* recipient the ECDH ephemeral key (an EC point) for deriving the
149+
* transaction output blinding factor. */
150+
class CConfidentialNonce : public CConfidentialCommitment<33, 2, 3>
151+
{
152+
public:
153+
CConfidentialNonce() { SetNull(); }
154+
};
155+
156+
/** A new asset issuance, or a reissuance (inflation) of an existing asset */
157+
class CAssetIssuance
158+
{
159+
public:
160+
// == 0
161+
// Indicates new asset issuance.
162+
// != 0
163+
// This is a revelation of the blinding factor for the input,
164+
// which shows that the input being spent is of the reissuance
165+
// capability type for the asset being inflated.
166+
uint256 assetBlindingNonce;
167+
168+
// New asset issuance:
169+
// This is a 32-byte nonce of no consensus-defined meaning,
170+
// but is used as additional entropy to the asset tag calculation.
171+
// This is used by higher-layer protocols for defining the
172+
// Ricardian contract governing the asset.
173+
// Existing asset reissuance:
174+
// The original asset entropy (combination of Ricardian contract
175+
// and outpoint used) which was used to generate the fixed asset
176+
// tag and reissuance tokens.
177+
uint256 assetEntropy;
178+
179+
// Both explicit and blinded issuance amounts are supported
180+
// (see class definition for CConfidentialValue for details).
181+
CConfidentialValue nAmount;
182+
183+
// If nonzero, specifies the number of asset issuance tokens to
184+
// generate. These tokens are made available to the outputs of the
185+
// generating transaction.
186+
CConfidentialValue nInflationKeys;
187+
188+
public:
189+
CAssetIssuance()
190+
{
191+
SetNull();
192+
}
193+
194+
ADD_SERIALIZE_METHODS;
195+
196+
template <typename Stream, typename Operation>
197+
inline void SerializationOp(Stream& s, Operation ser_action)
198+
{
199+
READWRITE(assetBlindingNonce);
200+
READWRITE(assetEntropy);
201+
READWRITE(nAmount);
202+
READWRITE(nInflationKeys);
203+
}
204+
205+
void SetNull() { nAmount.SetNull(); nInflationKeys.SetNull(); }
206+
bool IsNull() const { return (nAmount.IsNull() && nInflationKeys.IsNull()); }
207+
208+
friend bool operator==(const CAssetIssuance& a, const CAssetIssuance& b)
209+
{
210+
return a.assetBlindingNonce == b.assetBlindingNonce &&
211+
a.assetEntropy == b.assetEntropy &&
212+
a.nAmount == b.nAmount &&
213+
a.nInflationKeys == b.nInflationKeys;
214+
}
215+
216+
friend bool operator!=(const CAssetIssuance& a, const CAssetIssuance& b)
217+
{
218+
return !(a == b);
219+
}
220+
221+
std::string ToString() const;
222+
};
223+
224+
#endif // BITCOIN_PRIMITIVES_CONFIDENTIAL_H

0 commit comments

Comments
 (0)