From d0d7669ed8d28ae061cba10cc8381ad28682f2dc Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 14 Nov 2023 19:32:14 -0800 Subject: [PATCH] Add sign_deterministic and improve nonce generation. This commit changes the nonce generation to insert the secret key as the first 32 bytes of the randomness used to compute the nonce. This ensures that if a weak or no RNG is supplied, nonces are still unpredictable without knowledge of the secret key. We do not otherwise deviate from the original RedDSA choice of 80 bytes of randomness. --- Cargo.toml | 2 +- src/signing_key.rs | 34 +++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 471f3f8..c7d1e58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "decaf377-rdsa" edition = "2021" -version = "0.8.0" +version = "0.8.1" authors = ["Penumbra Labs "] readme = "README.md" license = "MIT OR Apache-2.0" diff --git a/src/signing_key.rs b/src/signing_key.rs index c783765..cd886a1 100644 --- a/src/signing_key.rs +++ b/src/signing_key.rs @@ -144,20 +144,32 @@ impl SigningKey { /// Create a signature for domain `D` on `msg` using this `SigningKey`. // Similar to signature::Signer but without boxed errors. pub fn sign(&self, mut rng: R, msg: &[u8]) -> Signature { - use crate::HStar; + let mut bonus_randomness = [0u8; 48]; + rng.fill_bytes(&mut bonus_randomness); + self.sign_inner(&bonus_randomness, msg) + } - // Choose a byte sequence uniformly at random of length (\ell_H + 128)/8 - // bytes, where \ell_H is the length of the hash output in bits. - // - // For decaf377-reddsa this is (512 + 128)/8 = 80. - let random_bytes = { - let mut bytes = [0; 80]; - rng.fill_bytes(&mut bytes); - bytes - }; + /// Create a signature for domain `D` on `msg` using this `SigningKey`. + /// + /// Prefer `sign`, unless you know you need deterministic signatures. + pub fn sign_deterministic(&self, msg: &[u8]) -> Signature { + let bonus_randomness = [0u8; 48]; + self.sign_inner(&bonus_randomness, msg) + } + + fn sign_inner(&self, bonus_randomness: &[u8; 48], msg: &[u8]) -> Signature { + use crate::HStar; + // We deviate from RedDSA as specified in the Zcash protocol spec and instead + // use a construction in line with Trevor Perrin's synthetic nonces: + // https://moderncrypto.org/mail-archive/curves/2017/000925.html + // Rather than choosing T to be 80 random bytes (\ell_H + 128)/8 as in RedDSA, + // we choose T to be 32-byte sk || 48-byte bonus_randomness. + // In this way, even in the case of an RNG failure, we fall back to secure but + // deterministic signing. let nonce = HStar::default() - .update(&random_bytes[..]) + .update(&self.sk.to_bytes()[..]) + .update(&bonus_randomness[..]) .update(&self.pk.bytes.bytes[..]) // XXX ugly .update(msg) .finalize();