Penetration Test Report (NCCGroup): NCC Group Zcash NU5 PublicReportFinal

Zcash NU5 Cryptography Review
Zcash
November 1, 2021
Preparedfor
SeanBowe
JackGrigg
DairaHopwood
TaylorHornby
YingTongLai
KrisNuttycombe
LarryRuane
StevenSmith
Preparedby
ParnianAlimi
AleksandarKircanski
ThomasPornin
Executive Summary
Synopsis github.com/zcash/zcash/pull/5232
In March 2021, Electric Coin Co. engaged NCC – signaturevalidationconsensusrules:https://github
Group to perform a review of the upcoming network .com/zcash/zcash/pull/5217
protocol upgrade NU5 to the Zcash protocol (code- – block header commitments: https://github.com/z
named “Orchard”). The review was to be performed cash/zcash/pull/5220
over multiple phases: first, the specification document • ForZIP225:
changes and the relevant ZIPs, then, in June 2021, the – Rustparsercode: https://github.com/zcash/librust
implementationitself. zcash/pull/375 and https://github.com/zcash/libru
stzcash/pull/398
Scope – C++ integration: https://github.com/zcash/zcash/p
The scope of the specification review consisted of the ull/5202
following: • ForZIP244:
– transactiondigestcomponents: https://github.com
• The Zcash protocol specification: https://zips.z.cas
/zcash/librustzcash/pull/375
h/protocol/nu5.pdf (reviewed version was 2021.1.19,
– transaction and signature digests: https://github.c
datedMarch17th,20211).
om/zcash/zcash/pull/5215 and https://github.com
• ThecontentsofZIPs216,224,225,244and252,asof
/zcash/zcash/pull/5219
March15th,2021:
• ZIP 316 specification (https://zips.z.cash/zip-0316)
– https://zips.z.cash/zip-0216
and implementation (https://github.com/zcash/libru
– https://zips.z.cash/zip-0224
stzcash/pull/383andhttps://github.com/zcash/librust
– https://zips.z.cash/zip-0225
zcash/pull/352)wereaddedtothescopeinthesecond
– https://zips.z.cash/zip-0244
phase.
– https://zips.z.cash/zip-0252
Limitations
Asfortheimplementationreview,scopeincluded:
WhileNCCGroupCryptographyServicescompletedthe
• ForZIP216: scopeofthesecurityauditthereweresomechallenges
– primaryfix: https://github.com/zkcrypto/jubjub/tre withscopeadjustmentsandcodenotbeingfinalizedat
e/f192388f3cad327868db4e8a58582083f24ef09f thestartoftheimplementationreviewphase.
– fix integration in librustzcash: https://github.c
FindingsandStrategicRecommendations
om/zcash/librustzcash/pull/396
– changes to consensus rules: https://github.com/z Noseriousissuewasdetectedduringthereview. Some
cash/zcash/pull/5213 potentialissueswerereported,butcannotbetriggered
• ForZIP224: inthecurrentimplementationandtheintendedusage
– PallasandVestacurves implementation: https://gi context; they might induce vulnerabilities later on if
thub.com/zcash/pasta_curves/tree/d8547d2326b some library code were later reused in a different
16b11b5c3e8ada231065111b51680 context (e.g. improper implementation of the random
– supportforRedPallasaddedintoaforkoftheredju pointselectionfunctionfortheiso-Pallasandiso-Vesta
bjubcrate: https://github.com/str4d/redjubjub/tre curves;seefindingNCC-E001151-002onpage6).
e/d5d8c5f3bb704bad8ae88fe4a29ae1f744774cb2
A description of the audit process and some relevant
– orchardcrate: https://github.com/zcash/orchard/t
remarkshavebeenassembledinAppendixBonpage13
ree/93a7f1db228479228f768e9d86dd5868e4c2ff
forthespecificationreview,andAppendixConpage18
1ewiththeexceptionofthe“circuit”part.
fortheimplementationreview. Noneoftheseremarks
– note encryption support (shared between Sapling
constitutes a security vulnerability, but they are still
andOrchard): https://github.com/zcash/librustzcas
worth mentioning and can be viewed as software
h/pull/358 and https://github.com/zcash/librustzc
engineeringissuesimpactinglong-termreadabilityand
ash/pull/390
maintenance of the code. Most of them relate to
– Orchard pool value tracking: https://github.com/z
casesofdeadcode,duplicatedcode,orambiguous(or
cash/zcash/pull/5228
lacking)documentation.
– Orchardproofverificationconsensusrules: https://
1Documenthash(SHA-256):fcfe26c583a23d9990bf3fdd836e86e7d8ecd1c89c5882a0516517ba65d21216
2 | ZcashNU5Review NCCGroup
Table of Findings
Foreachfinding,NCCGroupusesacompositeriskscorethattakesintoaccounttheseverityoftherisk,application’s
exposureanduserpopulation,technicaldifficultyofexploitation,andotherfactors. ForanexplanationofNCCGroup’s
riskratingandfindingcategorization,seeAppendixAonpage11.
Title Status ID Risk
InsufficientChecksinUnifiedAddressParser Fixed 004 Medium
IncorrectRandomPointGenerationandDecodingonIsogenousCurves Reported 002 Low
Non-Constant-TimeOperationsinPastaCurves Reported 003 Low
3 | ZcashNU5Review NCCGroup
Finding Details
Finding InsufficientChecksinUnifiedAddressParser
Risk Medium Impact: Low,Exploitability: Low
Identifier NCC-E001151-004
Status Fixed
Category DataValidation
Component librustzcash
Location components/zcash_address/src/kind/unified.rs,line90
Impact FailuretorejectUnifiedAddresses(UA)thatincludemorethanoneaddresstypecanleadto
ambiguouschoiceofreceiveraddress.
Description ZIP 316 clearly states that the “Senders MUST reject Unified Addresses in which the same
Typecode appears more than once, or that include both P2SH and P2PKH Transparent Ad-
dresses, or that contain only a Transparent Address”. The unified address parser (used by
thesender’swallet)parsestheinputasasequenceofTag-Length-Values,butdoesnotcheck
ifA)anaddresstypeisrepeated, B)P2SHandP2PKHarebothpresent, andC)atleastone
shieldedaddressisincluded. Thiscanbeseeninthecodebelow.
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
90
let encoded =
91
f4jumble::f4jumble_inv(buf).ok_or(ParseError::InvalidEncoding)?;
92
// Validate and strip trailing zero bytes.
93
let encoded = match encoded.split_at(encoded.len() - PADDING_LEN) {
94
(encoded, tail) if tail == &[0; PADDING_LEN][..] => Ok(encoded),
95
_ => Err(ParseError::InvalidEncoding),
96
}?;
97
98
iter::repeat(())
99
.scan(encoded, |encoded, _| match encoded {
100
// Base case: we've parsed the full encoding.
101
[] => None,
102
// The raw encoding of a Unified Address is a concatenation of:
103
// - typecode: byte
104
// - length: byte
105
// - addr: byte[length]
106
[typecode, length, data @ ..] if data.len() >= *length as usize => {
107
let (addr, rest) = data.split_at(*length as usize);
108
*encoded = rest;
109
Some(Receiver::try_from((*typecode, addr)))
110
}
111
// The encoding is truncated.
112
_ => Some(Err(ParseError::InvalidEncoding)),
113
})
114
.collect::<Result<_, _>>()
115
.map(Address)
116
}
117
The loop on line 99 scans, decodes, and appends receiver addresses to the Address list
withoutperforminganychecks. Asaconsequence,itisambiguouswhichaddressthecaller
ofthisAPI(Senderwallet)willusetocreatethetransaction. Inordertoexploitthis,anactive
attackerhastodecodetheUAandinserttheiraddressattheindextheypredictthesender
4 | ZcashNU5Review NCCGroup
walletwillprefer. Thisisnoteasierthansimplyreplacingreceiver’sUAwiththemaliciousUA,
thustheexploitabilityofthisfindingislow.
Recommendation AdapttheUnifiedAddressparsertocheckthatthereareatmostoneofeachaddresstypes
intheinputandthereisatmostonetypeoftransparentaddresspresent.
RetestResults NCC Group reviewed Pull Request 416 and observed that the Address construction API is
updated. Withthisfix,anAddresscanbeconstructedfrom:
1. AvectorofReceivers(viatheTryFrom<Vec<Receiver>>API),whichreturnsanerrorif
anyofthe3checksmentionedinthisfindingdonotpass.
Or,2. Abytearray(viatheTryFrom<&[u8]>API)whichfirstparsestheinputintoanarrayof
Receiversandifsuccessful,constructstheAddressfromit.
SinceanAddresscanonlybeconstructedafterpassingrequiredchecks,thisfindinghasbeen
markedasFixed.
5 | ZcashNU5Review NCCGroup
Finding IncorrectRandomPointGenerationandDecodingonIsogenousCurves
Risk Low Impact: Undetermined,Exploitability: None
Identifier NCC-E001151-002
Status Reported
Category Cryptography
Component pasta_curves
Location pasta_curves/src/curves.rs,lines69and633
Impact Invalidcurvepointsmaybecreatedifdecodingfrombytesorrandompointgenerationare
usedontheisogenouscurves(iso-Pallasandiso-Vesta). Sincetheimplementationsofthese
curvesonlyhavecratevisibility,andn