Penetration Test Report (Kudelski Security): KudelskiBulletproofsFinal

BulletproofsSecurityAudit Monero
Monero Bulletproofs Security Audit
FinalReport,--
FORPUBLICRELEASE
Sponsoredby
FORPUBLICRELEASE Pageof
BulletproofsSecurityAudit Monero
FORPUBLICRELEASE Pageof
Contents
 Summary 
 Findings 
. BP-F-: Unsafeuseofenvironmentvariables . . . . . . . . . . . . . . . 
. BP-F-: Lackofinputvalidationinprover . . . . . . . . . . . . . . . . . . 
. BP-F-: IntegeroverowinbulletproofLsizecomputation . . . . . . . . 
 Observations 
. BP-O-: PossibleDoSintheJavaversion . . . . . . . . . . . . . . . . . . 
. BP-O-: Unittestshavenotestvectors . . . . . . . . . . . . . . . . . . . 
. BP-O-: Functionsandvariablesnamingimprovements . . . . . . . . . 
. BP-O-: Conversionfunctionsleakamountrange . . . . . . . . . . . . . 
. BP-O-: Statisticalbiasinrandomnessusedfortesting . . . . . . . . . . 
. BP-O-: Conditionbasedonmodulo . . . . . . . . . . . . . . . . . . . 
. BP-O-: Undenedbehaviorshiftingsignedvalue . . . . . . . . . . . . 
 About 

 Summary
Monero is a decentralized, open-source cryptocurrency that provides strong privacy
protectionsthankstostate-of-the-artcryptographiccomponents.
Moneroisdeployinganewversionofitsprotocol,usingthe“bulletproofs“NIZKproofs
byBünzetal..
The Monero community hired Kudelski Security to perform a security assessment of
the new protocol’s implementation, based on the C++ implementation at
https://github.com/moneromooo-monero/bitmonero/ in the branch
“bp-multi-aggregation-pippenger”, under src/ringct. This implementation is
expectedtomatchtheJavaprototypeat
https://github.com/b-g-goodell/research-lab/blob/master/source-code/Stri
ngCT-java/src/how/monero/hodl/bulletproof/MultiBulletproof.java.
This document reports the security issues identied and our mitigation
recommendations, as well as our general assessment of the bulletproofs
implementation. A “status” section reports the feedback from Monero developers,
and includes a reference to the patches related to the issues reported. One issue
present in the initial report was removed from the nal report, after developers
noticedthatwehadmisunderstoodtheexpectedfunctionality.
Wereport:
potentialsecurityissuesofallegedlylowseverity
•
 observations related to general code safety, which we noticed in bulletproofs
•
https://eprint.iacr.org/2017/1066.pdf

BulletproofsSecurityAudit Monero
implementationsorinothercomponentoftheMonerocodebase.
We did not identify substantial discrepancies between the Java version and C version
of the integration of bulletproofs in RingCT. As suggested in this report, it would be
safer to unit test lower-level mathematical operations, both in terms of correctness
andmatchingwithestablishedtestvalues.
Having spent approximately  hours on the project, we would like to stress that
further analysis could well uncover dangerous code execution paths which we were
unable to follow due to limited time. The faults which we observed indicate that
further QA should be spent on the implementation. For example, the code base
wouldlikelybenetfromadditionalfuzztesting.
The audit was lead by Dr. Jean-Philippe Aumasson, VP Technology, jointly with Yolan
Romailler,CryptographyEngineer.
This audit was organized with the support of the OSTIF, thanks to their primary
sponsor, Private Internet Access, and the fundraising done by the Monero
Community.
FORPUBLICRELEASE Pageof
 Findings
Thissectionreportssecurityissuesfoundduringtheaudit.
The “status” section includes feedback from the developers received after delivering
ourdraftreport.
. BP-F-: Unsafe use of environment variables
Severity: Low
Description
Therelevantcodeisinbulletproofs.cc:
1 static inline rct::key multiexp(const std::vector<MultiexpData> &data, bool HiGi)
2 {
3 static const size_t STEP = getenv("STRAUS_STEP") ? atoi(getenv("STRAUS_STEP")) : 0;
4 if (HiGi || data.size() < 1000)
5 return straus(data, HiGi ? HiGi_cache: NULL, STEP);
6 else
7 return
Here getenv() gets the value of an environment variables, which is more likely to be
an attack vector than a cong le (with appropriate permissions). Furthermore, an
invalidvalueforSTRAUS_STEPwillnotbedetected:

BulletproofsSecurityAudit Monero
Ifastringthatisnotanumberisgiven,thenatoi()willjustreturn(andwill
•
beusedasaSTEPvalueinstraus())
If a negative value is given, then it will be cast to an unsigned size_t, potentially
•
changingalow-absolute-valuenegativenumbertoalargeinteger.
Thispotentiallyallowsanattackertoinuencetheeciencyoftheimplementationof
Straus’exponentiationalgorithm.
Recommendation
Use a conguration le (with proper permissions) rather than environment variables.
CheckthatthevalueofSTRAUS_STEPisapositiveinteger.
Status
This function no longer uses environment variables to set this value, as patched in
commit68f7606.
. BP-F-: Lack of input validation in prover
Severity:
Low
Description
bulletproof_PROVE() takes two arguments v and g (using the paper’s notation) that
areZ where p = 2252[PII_REDACTED][PII_REDACTED][PII_REDACTED]83648493.
p
However that function will not check that its arguments are less than p, and will
return a success error code upon invalid input. Also, degenerate values  and  are
also accepted as values for v and g. These values are not disallowed from the
FORPUBLICRELEASE Pageof
BulletproofsSecurityAudit Monero
mathematical specication of the function, but due to their specic behavior they
mayleadtoinsecureoperations.
Likewise, the elements of a proof in bulletproof_VERIFY() aren’t explicitly checked.
OnlytherepresentationofVhappenstobecheckedwithinge_frombytes_vartime().
Recommendation
CheckthattheargumentsbelongtoZ (ortotheirrespectivedomain).
p
Status
Inputscalarsarenowcheckedtoensuretheyarewithintheproperrangeintheprove
and verify routines, as patched in 68f7606. However, it should be noted that in the
proveroutine,anattackercanalwayssupplyinvalidscalarsregardlessofcodechecks.
. BP-F-: Integer overow in bulletproof L size computation
Severity:
Low
Description
size_t n_bulletproof_amounts()willoverowifproof.L.size()islargerthan:
1 size_t n_bulletproof_amounts(const Bulletproof &proof)
2 {
3 CHECK_AND_ASSERT_MES(proof.L.size() >= 6, 0, "Invalid bulletproof L size");
4 return 1 << (proof.L.size() - 6);
5 }
6
7 size_t n_bulletproof_amounts(const std::vector<Bulletproof> &proofs)
FORPUBLICRELEASE Pageof
BulletproofsSecurityAudit Monero
8 {
9 size_t n = 0;
10 for (const Bulletproof &proof: proofs)
11 {
12 size_t n2 = n_bulletproof_amounts(proof);
13 if (n2 == 0)
14 return 0;
15 n += n2;
16 }
17 return n;
18 }
Consequently, size_t n_bulletproof_amounts() will return  if any of the proofs in
thevectorreceivedislongerthan. (Notethatthiscandependonthecompiler,and
mightalsoresultinundenedbehavior.)
Thisfunctioniscalledinis_canonical_bulletproof_layout()whereareturnvalue
will cause the function to return true without entering the while loop, and therefore
withoutdoingthechecksitissupposedtodo.
When is_canonical_bulletproof_layout() is called in
core::handle_incoming_tx_accumulated_batch(), a true return value will lead the
proofs vector to be added to the delayed batch verication vector, despite the
invalideLvaluecontainedinoneoftheproofs.
This behavior, if unintended, may be exploited in order to force the verication of
proofswithnon-canonicallayout.
Recommendation
Havecorrectboundarycheckstoavoidtheoverow.
Status
Thishasbeenpatchedin68f7606.
FORPUBLICRELEASE Pageof
 Observations
Thissectionreportsvariousobservationsthatarenotsecurityissuestobexed.
. BP-O-: Possible DoS in the Java version
UnliketheCversionthatchecksthemaximumlengthMofaproofbeforesettingmaxMN
to2M,theJavaversionacceptsanyvalueofmaxLengthinthevericationfunction:
1 public static boolean VERIFY(ProofTuple[] proofs)
2 {
3 // Figure out which proof is longest
4 int maxLength = 0;
5 for (int p = 0; p < proofs.length; p++)
6 {
7 if (proofs[p].L.length > maxLength)
8 maxLength = proofs[p].L.length;
9 }
10 int