Implement randomization.
This commit is contained in:
parent
a3f0830bc1
commit
ead4727ded
|
@ -1,6 +1,6 @@
|
||||||
use std::{convert::TryFrom, marker::PhantomData};
|
use std::{convert::TryFrom, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{Error, Randomizer, Scalar, SigType, Signature};
|
use crate::{Error, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
||||||
|
|
||||||
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
||||||
/// an encoding of a RedJubJub public key.
|
/// an encoding of a RedJubJub public key.
|
||||||
|
@ -61,6 +61,21 @@ impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PublicKey<SpendAuth> {
|
||||||
|
/// Randomize this public key with the given `randomizer`.
|
||||||
|
///
|
||||||
|
/// Randomization is only supported for `SpendAuth` keys.
|
||||||
|
pub fn randomize(&self, randomizer: &Randomizer) -> PublicKey<SpendAuth> {
|
||||||
|
use crate::private::Sealed;
|
||||||
|
let point = &self.point + &(&SpendAuth::basepoint() * randomizer);
|
||||||
|
let bytes = PublicKeyBytes {
|
||||||
|
bytes: jubjub::AffinePoint::from(&point).to_bytes(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
PublicKey { bytes, point }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SigType> PublicKey<T> {
|
impl<T: SigType> PublicKey<T> {
|
||||||
pub(crate) fn from_secret(s: &Scalar) -> PublicKey<T> {
|
pub(crate) fn from_secret(s: &Scalar) -> PublicKey<T> {
|
||||||
let point = &T::basepoint() * s;
|
let point = &T::basepoint() * s;
|
||||||
|
@ -71,11 +86,6 @@ impl<T: SigType> PublicKey<T> {
|
||||||
PublicKey { bytes, point }
|
PublicKey { bytes, point }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Randomize this public key with the given `randomizer`.
|
|
||||||
pub fn randomize(&self, _randomizer: Randomizer) -> PublicKey<T> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify a purported `signature` over `msg` made by this public key.
|
/// Verify a purported `signature` over `msg` made by this public key.
|
||||||
// This is similar to impl signature::Verifier but without boxed errors
|
// This is similar to impl signature::Verifier but without boxed errors
|
||||||
pub fn verify(&self, msg: &[u8], signature: &Signature<T>) -> Result<(), Error> {
|
pub fn verify(&self, msg: &[u8], signature: &Signature<T>) -> Result<(), Error> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{PublicKey, Randomizer, Scalar, SigType, Signature};
|
use crate::{PublicKey, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
||||||
|
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
|
@ -37,6 +37,15 @@ impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SecretKey<SpendAuth> {
|
||||||
|
/// Randomize this public key with the given `randomizer`.
|
||||||
|
pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey<SpendAuth> {
|
||||||
|
let sk = &self.sk + randomizer;
|
||||||
|
let pk = PublicKey::from_secret(&sk);
|
||||||
|
SecretKey { sk, pk }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SigType> SecretKey<T> {
|
impl<T: SigType> SecretKey<T> {
|
||||||
/// Generate a new secret key.
|
/// Generate a new secret key.
|
||||||
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SecretKey<T> {
|
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SecretKey<T> {
|
||||||
|
@ -49,11 +58,6 @@ impl<T: SigType> SecretKey<T> {
|
||||||
SecretKey { sk, pk }
|
SecretKey { sk, pk }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Randomize this public key with the given `randomizer`.
|
|
||||||
pub fn randomize(&self, _randomizer: Randomizer) -> PublicKey<T> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a signature of type `T` on `msg` using this `SecretKey`.
|
/// Create a signature of type `T` on `msg` using this `SecretKey`.
|
||||||
// Similar to signature::Signer but without boxed errors.
|
// Similar to signature::Signer but without boxed errors.
|
||||||
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
|
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
|
||||||
|
|
|
@ -96,18 +96,20 @@ fn tweak_strategy() -> impl Strategy<Value = Tweak> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use rand_chacha::ChaChaRng;
|
||||||
|
use rand_core::SeedableRng;
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tweak_signature(
|
fn tweak_signature(
|
||||||
tweaks in prop::collection::vec(tweak_strategy(), (0,5)),
|
tweaks in prop::collection::vec(tweak_strategy(), (0,5)),
|
||||||
rng_seed in any::<u64>(),
|
rng_seed in any::<u64>(),
|
||||||
) {
|
) {
|
||||||
use rand_core::SeedableRng;
|
|
||||||
|
|
||||||
// Use a deterministic RNG so that test failures can be reproduced.
|
// Use a deterministic RNG so that test failures can be reproduced.
|
||||||
// Seeding with 64 bits of entropy is INSECURE and this code should
|
// Seeding with 64 bits of entropy is INSECURE and this code should
|
||||||
// not be copied outside of this test!
|
// not be copied outside of this test!
|
||||||
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(rng_seed);
|
let mut rng = ChaChaRng::seed_from_u64(rng_seed);
|
||||||
|
|
||||||
// Create a test case for each signature type.
|
// Create a test case for each signature type.
|
||||||
let msg = b"test message for proptests";
|
let msg = b"test message for proptests";
|
||||||
|
@ -123,4 +125,30 @@ proptest! {
|
||||||
assert!(binding.check());
|
assert!(binding.check());
|
||||||
assert!(spendauth.check());
|
assert!(spendauth.check());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn randomization_commutes_with_pubkey_homomorphism(rng_seed in any::<u64>()) {
|
||||||
|
// Use a deterministic RNG so that test failures can be reproduced.
|
||||||
|
// Seeding with 64 bits of entropy is INSECURE and this code should
|
||||||
|
// not be copied outside of this test!
|
||||||
|
let mut rng = ChaChaRng::seed_from_u64(rng_seed);
|
||||||
|
|
||||||
|
let r = {
|
||||||
|
// XXX-jubjub: better API for this
|
||||||
|
let mut bytes = [0; 64];
|
||||||
|
rng.fill_bytes(&mut bytes[..]);
|
||||||
|
Randomizer::from_bytes_wide(&bytes)
|
||||||
|
};
|
||||||
|
|
||||||
|
let sk = SecretKey::<SpendAuth>::new(&mut rng);
|
||||||
|
let pk = PublicKey::from(&sk);
|
||||||
|
|
||||||
|
let sk_r = sk.randomize(&r);
|
||||||
|
let pk_r = pk.randomize(&r);
|
||||||
|
|
||||||
|
let pk_r_via_sk_rand: [u8; 32] = PublicKeyBytes::from(PublicKey::from(&sk_r)).into();
|
||||||
|
let pk_r_via_pk_rand: [u8; 32] = PublicKeyBytes::from(pk_r).into();
|
||||||
|
|
||||||
|
assert_eq!(pk_r_via_pk_rand, pk_r_via_sk_rand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue