port improvements from Zebra (#40)

* simplify fmt::Debug impls with new hex_if_possible()

* Update src/signature.rs authors

Co-authored-by: Deirdre Connolly <deirdre@zfnd.org>
This commit is contained in:
Conrado Gouvea 2023-01-30 18:16:53 -03:00 committed by GitHub
parent 31f29420c8
commit 805ef4b5c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 11 deletions

View File

@ -25,6 +25,7 @@ features = ["nightly"]
blake2b_simd = { version = "1", default-features = false }
byteorder = { version = "1.4", default-features = false }
group = { version = "0.12", default-features = false }
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc"] }
jubjub = { version = "0.9", default-features = false }
pasta_curves = { version = "0.4", default-features = false }
rand_core = { version = "0.6", default-features = false }
@ -53,7 +54,7 @@ features = ["alloc"]
[features]
std = ["blake2b_simd/std", "thiserror", "zeroize", "alloc",
"serde"] # conditional compilation for serde not complete (issue #9)
alloc = []
alloc = ["hex"]
nightly = []
default = ["std"]

View File

@ -30,8 +30,10 @@ use rand_core::{CryptoRng, RngCore};
use crate::{private::SealedScalar, scalar_mul::VartimeMultiscalarMul, *};
// Shim to generate a random 128bit value in a [u64; 4], without
// importing `rand`.
/// Shim to generate a random 128 bit value in a `[u64; 4]`, without
/// importing `rand`.
///
/// The final 128 bits are zero.
fn gen_128_bits<R: RngCore + CryptoRng>(mut rng: R) -> [u64; 4] {
let mut bytes = [0u64; 4];
bytes[0] = rng.next_u64();
@ -39,13 +41,23 @@ fn gen_128_bits<R: RngCore + CryptoRng>(mut rng: R) -> [u64; 4] {
bytes
}
/// Inner type of a batch verification item.
///
/// This struct exists to allow batch processing to be decoupled from the
/// lifetime of the message. This is useful when using the batch verification
/// API in an async context
///
/// The different enum variants are for the different signature types which use
/// different basepoints for computation: SpendAuth and Binding signatures.
#[derive(Clone, Debug)]
enum Inner<S: SpendAuth, B: Binding<Scalar = S::Scalar, Point = S::Point>> {
/// A RedDSA signature using the SpendAuth generator group element.
SpendAuth {
vk_bytes: VerificationKeyBytes<S>,
sig: Signature<S>,
c: S::Scalar,
},
/// A RedDSA signature using the Binding generator group element.
Binding {
vk_bytes: VerificationKeyBytes<B>,
sig: Signature<B>,

View File

@ -119,3 +119,15 @@ pub(crate) mod private {
}
}
}
/// Return the given byte array as a hex-encoded string.
#[cfg(feature = "alloc")]
pub(crate) fn hex_if_possible(bytes: &[u8]) -> alloc::string::String {
hex::encode(bytes)
}
/// Return the given byte array.
#[cfg(not(feature = "alloc"))]
pub(crate) fn hex_if_possible(bytes: &[u8]) -> &[u8] {
bytes
}

View File

@ -15,13 +15,17 @@ use crate::{private, SigType};
#[cfg(feature = "alloc")]
use crate::scalar_mul::{LookupTable5, NonAdjacentForm, VartimeMultiscalarMul};
/// The byte-encoding of the basepoint for `OrchardSpendAuthSig`.
/// The byte-encoding of the basepoint for the Orchard `SpendAuthSig` on the [Pallas curve][pallasandvesta].
///
/// [pallasandvesta]: https://zips.z.cash/protocol/nu5.pdf#pallasandvesta
// Reproducible by pallas::Point::hash_to_curve("z.cash:Orchard")(b"G").to_bytes()
const ORCHARD_SPENDAUTHSIG_BASEPOINT_BYTES: [u8; 32] = [
99, 201, 117, 184, 132, 114, 26, 141, 12, 161, 112, 123, 227, 12, 127, 12, 95, 68, 95, 62, 124,
24, 141, 59, 6, 214, 241, 40, 179, 35, 85, 183,
];
/// The byte-encoding of the basepoint for `OrchardBindingSig`.
/// The byte-encoding of the basepoint for the Orchard `BindingSig` on the Pallas curve.
// Reproducible by pallas::Point::hash_to_curve("z.cash:Orchard-cv")(b"r").to_bytes()
const ORCHARD_BINDINGSIG_BASEPOINT_BYTES: [u8; 32] = [
145, 90, 60, 136, 104, 198, 195, 14, 47, 128, 144, 238, 69, 215, 110, 64, 72, 32, 141, 234, 91,
35, 102, 79, 187, 9, 164, 15, 85, 68, 244, 7,

View File

@ -10,6 +10,8 @@
// - Henry de Valence <hdevalence@hdevalence.ca>
// - Deirdre Connolly <deirdre@zfnd.org>
//! Traits and types that support variable-time multiscalar multiplication.
use alloc::vec::Vec;
use core::{borrow::Borrow, fmt::Debug};
@ -65,7 +67,9 @@ pub trait VartimeMultiscalarMul {
impl NonAdjacentForm for jubjub::Scalar {
/// Compute a width-\\(w\\) "Non-Adjacent Form" of this scalar.
///
/// Thanks to curve25519-dalek
/// Thanks to [`curve25519-dalek`].
///
/// [`curve25519-dalek`]: https://github.com/dalek-cryptography/curve25519-dalek/blob/3e189820da03cc034f5fa143fc7b2ccb21fffa5e/src/scalar.rs#L907
fn non_adjacent_form(&self, w: usize) -> [i8; 256] {
// required by the NAF definition
debug_assert!(w >= 2);
@ -160,6 +164,16 @@ impl VartimeMultiscalarMul for ExtendedPoint {
type Scalar = jubjub::Scalar;
type Point = ExtendedPoint;
/// Variable-time multiscalar multiplication using a non-adjacent form of
/// width (5).
///
/// The non-adjacent form has signed, odd digits. Using only odd digits
/// halves the table size (since we only need odd multiples), or gives fewer
/// additions for the same table size.
///
/// As the name implies, the runtime varies according to the values of the
/// inputs, thus is not safe for computing over secret data, but is great
/// for computing over public data, such as validating signatures.
#[allow(non_snake_case)]
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<ExtendedPoint>
where

View File

@ -6,14 +6,15 @@
//
// Authors:
// - Henry de Valence <hdevalence@hdevalence.ca>
// - Conrado Gouvea <conradoplg@gmail.com>
//! RedDSA Signatures
use core::marker::PhantomData;
use core::{fmt, marker::PhantomData};
use crate::SigType;
use crate::{hex_if_possible, SigType};
/// A RedDSA signature.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Signature<T: SigType> {
pub(crate) r_bytes: [u8; 32],
@ -21,6 +22,15 @@ pub struct Signature<T: SigType> {
pub(crate) _marker: PhantomData<T>,
}
impl<T: SigType> fmt::Debug for Signature<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Signature")
.field("r_bytes", &hex_if_possible(&self.r_bytes))
.field("s_bytes", &hex_if_possible(&self.s_bytes))
.finish()
}
}
impl<T: SigType> From<[u8; 64]> for Signature<T> {
fn from(bytes: [u8; 64]) -> Signature<T> {
let mut r_bytes = [0; 32];

View File

@ -10,13 +10,14 @@
use core::{
convert::{TryFrom, TryInto},
fmt,
hash::Hash,
marker::PhantomData,
};
use group::{cofactor::CofactorGroup, ff::PrimeField, GroupEncoding};
use crate::{Error, Randomizer, SigType, Signature, SpendAuth};
use crate::{hex_if_possible, Error, Randomizer, SigType, Signature, SpendAuth};
/// A refinement type for `[u8; 32]` indicating that the bytes represent
/// an encoding of a RedDSA verification key.
@ -24,13 +25,21 @@ use crate::{Error, Randomizer, SigType, Signature, SpendAuth};
/// This is useful for representing a compressed verification key; the
/// [`VerificationKey`] type in this library holds other decompressed state
/// used in signature verification.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VerificationKeyBytes<T: SigType> {
pub(crate) bytes: [u8; 32],
pub(crate) _marker: PhantomData<T>,
}
impl<T: SigType> fmt::Debug for VerificationKeyBytes<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VerificationKeyBytes")
.field("bytes", &hex_if_possible(&self.bytes))
.finish()
}
}
impl<T: SigType> From<[u8; 32]> for VerificationKeyBytes<T> {
fn from(bytes: [u8; 32]) -> VerificationKeyBytes<T> {
VerificationKeyBytes {