ed25519-zebra/src/verification_key.rs

225 lines
7.5 KiB
Rust
Raw Normal View History

2022-05-05 06:40:29 -07:00
use core::convert::{TryFrom, TryInto};
2020-01-22 14:57:26 -08:00
2020-01-22 16:58:18 -08:00
use curve25519_dalek::{
digest::Update,
2020-01-22 16:58:18 -08:00
edwards::{CompressedEdwardsY, EdwardsPoint},
scalar::Scalar,
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
traits::IsIdentity,
2020-01-22 16:58:18 -08:00
};
use sha2::Sha512;
use zeroize::DefaultIsZeroes;
2020-01-22 14:57:26 -08:00
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
use crate::{Error, Signature};
2020-01-22 14:57:26 -08:00
2020-01-24 12:55:43 -08:00
/// A refinement type for `[u8; 32]` indicating that the bytes represent an
/// encoding of an Ed25519 verification key.
2020-01-22 14:57:26 -08:00
///
/// This is useful for representing an encoded verification key, while the
/// [`VerificationKey`] type in this library caches other decoded state used in
/// signature verification.
2020-01-24 12:55:43 -08:00
///
/// A `VerificationKeyBytes` can be used to verify a single signature using the
2020-01-24 12:55:43 -08:00
/// following idiom:
/// ```
2022-05-05 06:40:29 -07:00
/// use core::convert::TryFrom;
2020-01-24 12:55:43 -08:00
/// # use rand::thread_rng;
/// # use ed25519_zebra::*;
/// # let msg = b"Zcash";
/// # let sk = SigningKey::new(thread_rng());
2020-01-24 12:55:43 -08:00
/// # let sig = sk.sign(msg);
/// # let vk_bytes = VerificationKeyBytes::from(&sk);
/// VerificationKey::try_from(vk_bytes)
/// .and_then(|vk| vk.verify(&sig, msg));
2020-01-24 12:55:43 -08:00
/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2020-01-22 14:57:26 -08:00
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VerificationKeyBytes(pub(crate) [u8; 32]);
2020-01-22 14:57:26 -08:00
impl core::fmt::Debug for VerificationKeyBytes {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.debug_tuple("VerificationKeyBytes")
.field(&hex::encode(&self.0))
.finish()
}
}
impl AsRef<[u8]> for VerificationKeyBytes {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl TryFrom<&[u8]> for VerificationKeyBytes {
type Error = Error;
fn try_from(slice: &[u8]) -> Result<VerificationKeyBytes, Error> {
if slice.len() == 32 {
let mut bytes = [0u8; 32];
bytes[..].copy_from_slice(slice);
Ok(bytes.into())
} else {
Err(Error::InvalidSliceLength)
}
}
}
impl From<[u8; 32]> for VerificationKeyBytes {
fn from(bytes: [u8; 32]) -> VerificationKeyBytes {
VerificationKeyBytes(bytes)
2020-01-22 14:57:26 -08:00
}
}
impl From<VerificationKeyBytes> for [u8; 32] {
fn from(refined: VerificationKeyBytes) -> [u8; 32] {
2020-01-22 14:57:26 -08:00
refined.0
}
}
/// A valid Ed25519 verification key.
///
/// This is also called a public key by other implementations.
2020-01-22 14:57:26 -08:00
///
/// This type holds decompressed state used in signature verification; if the
/// verification key may not be used immediately, it is probably better to use
/// [`VerificationKeyBytes`], which is a refinement type for `[u8; 32]`.
2020-01-22 14:57:26 -08:00
///
/// ## Zcash-specific consensus properties
2020-01-22 14:57:26 -08:00
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// Ed25519 checks are described in [§5.4.5][ps] of the Zcash protocol specification and in
/// [ZIP 215]. The verification criteria for an (encoded) verification key `A_bytes` are:
2020-01-22 14:57:26 -08:00
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// * `A_bytes` MUST be an encoding of a point `A` on the twisted Edwards form of
/// Curve25519, and non-canonical encodings MUST be accepted;
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#concreteed25519
2020-01-22 14:57:26 -08:00
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "VerificationKeyBytes"))]
#[cfg_attr(feature = "serde", serde(into = "VerificationKeyBytes"))]
#[allow(non_snake_case)]
pub struct VerificationKey {
pub(crate) A_bytes: VerificationKeyBytes,
pub(crate) minus_A: EdwardsPoint,
2020-01-22 14:57:26 -08:00
}
impl From<VerificationKey> for VerificationKeyBytes {
fn from(vk: VerificationKey) -> VerificationKeyBytes {
vk.A_bytes
2020-01-22 14:57:26 -08:00
}
}
impl AsRef<[u8]> for VerificationKey {
fn as_ref(&self) -> &[u8] {
&self.A_bytes.0[..]
}
}
impl Default for VerificationKey {
fn default() -> VerificationKey {
let identity: EdwardsPoint = Default::default();
let identity_bytes = identity.compress().to_bytes();
VerificationKey {
A_bytes: VerificationKeyBytes::from(identity_bytes),
minus_A: -identity,
}
}
}
impl DefaultIsZeroes for VerificationKey {}
impl From<VerificationKey> for [u8; 32] {
fn from(vk: VerificationKey) -> [u8; 32] {
vk.A_bytes.0
2020-01-22 14:57:26 -08:00
}
}
impl TryFrom<VerificationKeyBytes> for VerificationKey {
2020-01-22 14:57:26 -08:00
type Error = Error;
#[allow(non_snake_case)]
fn try_from(bytes: VerificationKeyBytes) -> Result<Self, Self::Error> {
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
// * `A_bytes` and `R_bytes` MUST be encodings of points `A` and `R` respectively on the
// twisted Edwards form of Curve25519, and non-canonical encodings MUST be accepted;
let A = CompressedEdwardsY(bytes.0)
2020-01-22 14:57:26 -08:00
.decompress()
.ok_or(Error::MalformedPublicKey)?;
Ok(VerificationKey {
A_bytes: bytes,
minus_A: -A,
})
2020-01-22 14:57:26 -08:00
}
}
impl TryFrom<&[u8]> for VerificationKey {
type Error = Error;
fn try_from(slice: &[u8]) -> Result<VerificationKey, Error> {
VerificationKeyBytes::try_from(slice).and_then(|vkb| vkb.try_into())
}
}
impl TryFrom<[u8; 32]> for VerificationKey {
2020-01-22 14:57:26 -08:00
type Error = Error;
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
VerificationKeyBytes::from(bytes).try_into()
2020-01-22 14:57:26 -08:00
}
}
impl VerificationKey {
2020-01-22 14:57:26 -08:00
/// Verify a purported `signature` on the given `msg`.
///
/// ## Zcash-specific consensus properties
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// Ed25519 checks are described in [§5.4.5][ps] of the Zcash protocol specification and in
/// [ZIP215]. The verification criteria for an (encoded) signature `(R_bytes, s_bytes)` with
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// (encoded) verification key `A_bytes` are:
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// * `A_bytes` and `R_bytes` MUST be encodings of points `A` and `R` respectively on the
/// twisted Edwards form of Curve25519, and non-canonical encodings MUST be accepted;
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// * `s_bytes` MUST represent an integer `s` less than `l`, the order of the prime-order
/// subgroup of Curve25519;
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// * the verification equation `[8][s]B = [8]R + [8][k]A` MUST be satisfied;
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// * the alternate verification equation `[s]B = R + [k]A`, allowed by RFC 8032, MUST NOT be
/// used.
///
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#concreteed25519
2023-03-14 11:57:25 -07:00
/// [ZIP215]: https://zips.z.cash/zip-0215
2020-01-22 16:58:18 -08:00
pub fn verify(&self, signature: &Signature, msg: &[u8]) -> Result<(), Error> {
let k = Scalar::from_hash(
Sha512::default()
.chain(&signature.R_bytes[..])
.chain(&self.A_bytes.0[..])
.chain(msg),
);
self.verify_prehashed(signature, k)
}
/// Verify a signature with a prehashed `k` value. Note that this is not the
/// same as "prehashing" in RFC8032.
#[allow(non_snake_case)]
pub(crate) fn verify_prehashed(&self, signature: &Signature, k: Scalar) -> Result<(), Error> {
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
// `s_bytes` MUST represent an integer less than the prime `l`.
let s = Option::<Scalar>::from(Scalar::from_canonical_bytes(signature.s_bytes))
.ok_or(Error::InvalidSignature)?;
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
// `R_bytes` MUST be an encoding of a point on the twisted Edwards form of Curve25519.
let R = CompressedEdwardsY(signature.R_bytes)
.decompress()
.ok_or(Error::InvalidSignature)?;
// We checked the encoding of A_bytes when constructing `self`.
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
// [8][s]B = [8]R + [8][k]A
// <=> [8]R = [8][s]B - [8][k]A
// <=> 0 = [8](R - ([s]B - [k]A))
// <=> 0 = [8](R - R') where R' = [s]B - [k]A
let R_prime = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &self.minus_A, &s);
2020-01-22 16:58:18 -08:00
Implement ZIP 215 validation rules. (#24) * Implement ZIP 215 validation rules. These have the effect that batched and singleton verification are now equivalent. * Add ZIP 215 conformance tests. This test constructs signatures on the message "Zcash" using small-order verification keys, some with canonical and some with non-canonical encodings of points. All of these signatures should pass verification under the ZIP 215 rules, but most of them should fail verification under legacy rules. These tests exercise all of the special-case behaviors from the specific version of libsodium used by Zcashd: * the all-zero check for the verification key; * the excluded point encodings for the signature's R value; * the choice to test equality of the encoded bytes of the recomputed R value rather than on the projective coordinates of the two points. Running ``` cargo test -- --nocapture ``` will print a hex-formatted list of the test cases, which can also be found here: https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7 * Update spec links. Thanks to @ebfull for pointing this out. * No ... there is another. @ebfull pointed out that two test cases were duplicates. The cause was that I misread the RFC8032 check was checking for the non-canonical encoding of the identity point that NCC Group apparently brought up. Carefully analyzing all the cases instead of assuming reveals there is another non-canonically encoded point (of order 2). * Change formatting of printed test cases.
2020-07-06 19:40:20 -07:00
if (R - R_prime).mul_by_cofactor().is_identity() {
2020-01-22 16:58:18 -08:00
Ok(())
} else {
Err(Error::InvalidSignature)
}
2020-01-22 14:57:26 -08:00
}
}