Don't reject small-order verification keys

Fixes ZcashFoundation/redjubjub#127.
This commit is contained in:
Jack Grigg 2021-09-06 20:15:55 +01:00
parent 3db05e29f7
commit a34b04c0ad
3 changed files with 33 additions and 8 deletions

View File

@ -2,6 +2,21 @@
Entries are listed in reverse chronological order.
## Unreleased
* Fixed a bug where small-order verification keys (including the identity) were
handled inconsistently: the `VerificationKey` parsing logic rejected them, but
the identity `VerificationKey` could be produced from the zero `SigningKey`.
The behaviour is now to consistently accept all small-order verification keys,
matching the RedDSA specification.
* Downstream users who currently rely on the inconsistent behaviour (for e.g.
consensus compatibility, either explicitly wanting to reject small-order
verification keys, or on the belief that this crate implemented the RedDSA
specification) should continue to use previous versions of this crate, until
they can either move the checks into their own code, or migrate their
consensus rules to match the RedDSA specification.
## 0.2.2
* Make `batch::Item: Clone + Debug` and add `batch::Item::verify_single`

View File

@ -99,12 +99,13 @@ impl<T: SigType> TryFrom<VerificationKeyBytes<T>> for VerificationKey<T> {
let maybe_point = jubjub::AffinePoint::from_bytes(bytes.bytes);
if maybe_point.is_some().into() {
let point: jubjub::ExtendedPoint = maybe_point.unwrap().into();
// This checks that the verification key is not of small order.
if <bool>::from(point.is_small_order()) == false {
Ok(VerificationKey { point, bytes })
} else {
Err(Error::MalformedVerificationKey)
}
// Note that small-order verification keys (including the identity) are not
// rejected here. Previously they were rejected, but this was a bug as the
// RedDSA specification allows them. Zcash Sapling rejects small-order points
// for the RedJubjub spend authorization key rk; this now occurs separately.
// Meanwhile, Zcash Orchard uses a prime-order group, so the only small-order
// point would be the identity, which is allowed in Orchard.
Ok(VerificationKey { point, bytes })
} else {
Err(Error::MalformedVerificationKey)
}

View File

@ -5,11 +5,20 @@ use jubjub::{AffinePoint, Fq};
use redjubjub::*;
#[test]
fn smallorder_publickey_fails() {
fn identity_publickey_passes() {
let identity = AffinePoint::identity();
assert_eq!(<bool>::from(identity.is_small_order()), true);
let bytes = identity.to_bytes();
let pk_bytes = VerificationKeyBytes::<SpendAuth>::from(bytes);
assert!(VerificationKey::<SpendAuth>::try_from(pk_bytes).is_ok());
}
#[test]
fn smallorder_publickey_passes() {
// (1,0) is a point of order 4 on any Edwards curve
let order4 = AffinePoint::from_raw_unchecked(Fq::one(), Fq::zero());
assert_eq!(<bool>::from(order4.is_small_order()), true);
let bytes = order4.to_bytes();
let pk_bytes = VerificationKeyBytes::<SpendAuth>::from(bytes);
assert!(VerificationKey::<SpendAuth>::try_from(pk_bytes).is_err());
assert!(VerificationKey::<SpendAuth>::try_from(pk_bytes).is_ok());
}