Merge pull request #108 from zcash/102-sign-with-rsk

builder: Store alpha and use it to derive rsk for signing spends
This commit is contained in:
str4d 2021-06-11 14:42:16 +01:00 committed by GitHub
commit 8464df6e46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 38 deletions

View File

@ -154,7 +154,7 @@ impl ActionInfo {
cv_net, cv_net,
SigningMetadata { SigningMetadata {
dummy_ask: self.spend.dummy_sk.as_ref().map(SpendAuthorizingKey::from), dummy_ask: self.spend.dummy_sk.as_ref().map(SpendAuthorizingKey::from),
ak, parts: SigningParts { ak, alpha },
}, },
), ),
Circuit {}, Circuit {},
@ -325,6 +325,16 @@ impl Builder {
} }
} }
/// The parts needed to sign an [`Action`].
#[derive(Debug)]
pub struct SigningParts {
/// The spend validating key for this action. Used to match spend authorizing keys to
/// actions they can create signatures for.
ak: SpendValidatingKey,
/// The randomization needed to derive the actual signing key for this note.
alpha: pallas::Scalar,
}
/// Marker for an unauthorized bundle, with a proof but no signatures. /// Marker for an unauthorized bundle, with a proof but no signatures.
#[derive(Debug)] #[derive(Debug)]
pub struct Unauthorized { pub struct Unauthorized {
@ -345,9 +355,7 @@ pub struct SigningMetadata {
/// These keys are used automatically in [`Bundle<Unauthorized>::prepare`] or /// These keys are used automatically in [`Bundle<Unauthorized>::prepare`] or
/// [`Bundle<Unauthorized>::apply_signatures`] to sign dummy spends. /// [`Bundle<Unauthorized>::apply_signatures`] to sign dummy spends.
dummy_ask: Option<SpendAuthorizingKey>, dummy_ask: Option<SpendAuthorizingKey>,
/// The spend validating key for this action. Used to match spend authorizing keys to parts: SigningParts,
/// actions they can create signatures for.
ak: SpendValidatingKey,
} }
/// Marker for a partially-authorized bundle, in the process of being signed. /// Marker for a partially-authorized bundle, in the process of being signed.
@ -359,7 +367,27 @@ pub struct PartiallyAuthorized {
} }
impl Authorization for PartiallyAuthorized { impl Authorization for PartiallyAuthorized {
type SpendAuth = (Option<redpallas::Signature<SpendAuth>>, SpendValidatingKey); type SpendAuth = MaybeSigned;
}
/// A heisen[`Signature`] for a particular [`Action`].
///
/// [`Signature`]: redpallas::Signature
#[derive(Debug)]
pub enum MaybeSigned {
/// The information needed to sign this [`Action`].
SigningMetadata(SigningParts),
/// The signature for this [`Action`].
Signature(redpallas::Signature<SpendAuth>),
}
impl MaybeSigned {
fn finalize(self) -> Result<redpallas::Signature<SpendAuth>, Error> {
match self {
Self::Signature(sig) => Ok(sig),
_ => Err(Error::MissingSignatures),
}
}
} }
impl<V> Bundle<Unauthorized, V> { impl<V> Bundle<Unauthorized, V> {
@ -373,12 +401,12 @@ impl<V> Bundle<Unauthorized, V> {
) -> Bundle<PartiallyAuthorized, V> { ) -> Bundle<PartiallyAuthorized, V> {
self.authorize( self.authorize(
&mut rng, &mut rng,
|rng, _, SigningMetadata { dummy_ask, ak }| { |rng, _, SigningMetadata { dummy_ask, parts }| {
( // We can create signatures for dummy spends immediately.
// We can create signatures for dummy spends immediately. dummy_ask
dummy_ask.map(|ask| ask.sign(rng, &sighash)), .map(|ask| ask.randomize(&parts.alpha).sign(rng, &sighash))
ak, .map(MaybeSigned::Signature)
) .unwrap_or(MaybeSigned::SigningMetadata(parts))
}, },
|rng, unauth| PartiallyAuthorized { |rng, unauth| PartiallyAuthorized {
proof: unauth.proof, proof: unauth.proof,
@ -412,17 +440,11 @@ impl<V> Bundle<PartiallyAuthorized, V> {
let expected_ak = ask.into(); let expected_ak = ask.into();
self.authorize( self.authorize(
&mut rng, &mut rng,
|rng, partial, (sig, ak)| { |rng, partial, maybe| match maybe {
( MaybeSigned::SigningMetadata(parts) if parts.ak == expected_ak => {
sig.or_else(|| { MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(rng, &partial.sighash))
if ak == expected_ak { }
Some(ask.sign(rng, &partial.sighash)) s => s,
} else {
None
}
}),
ak,
)
}, },
|_, partial| partial, |_, partial| partial,
) )
@ -434,10 +456,7 @@ impl<V> Bundle<PartiallyAuthorized, V> {
pub fn finalize(self) -> Result<Bundle<Authorized, V>, Error> { pub fn finalize(self) -> Result<Bundle<Authorized, V>, Error> {
self.try_authorize( self.try_authorize(
&mut (), &mut (),
|_, _, (sig, _)| match sig { |_, _, maybe| maybe.finalize(),
Some(sig) => Ok(sig),
None => Err(Error::MissingSignatures),
},
|_, partial| { |_, partial| {
Ok(Authorized::from_parts( Ok(Authorized::from_parts(
partial.proof, partial.proof,
@ -594,12 +613,12 @@ mod tests {
builder builder
.add_recipient(None, recipient, NoteValue::from_raw(5000), None) .add_recipient(None, recipient, NoteValue::from_raw(5000), None)
.unwrap(); .unwrap();
let bundle: Bundle<Authorized, i64> = dbg!(builder let bundle: Bundle<Authorized, i64> = builder
.build(&mut rng, &pk) .build(&mut rng, &pk)
.unwrap() .unwrap()
.prepare(&mut rng, [0; 32])) .prepare(&mut rng, [0; 32])
.finalize() .finalize()
.unwrap(); .unwrap();
assert_eq!(bundle.value_balance(), &(-5000)) assert_eq!(bundle.value_balance(), &(-5000))
} }
} }

View File

@ -8,7 +8,7 @@ use fpe::ff1::{BinaryNumeralString, FF1};
use group::GroupEncoding; use group::GroupEncoding;
use halo2::arithmetic::FieldExt; use halo2::arithmetic::FieldExt;
use pasta_curves::pallas; use pasta_curves::pallas;
use rand::{CryptoRng, RngCore}; use rand::RngCore;
use subtle::CtOption; use subtle::CtOption;
use crate::{ use crate::{
@ -76,13 +76,11 @@ impl SpendAuthorizingKey {
to_scalar(PrfExpand::OrchardAsk.expand(&sk.0)) to_scalar(PrfExpand::OrchardAsk.expand(&sk.0))
} }
/// Creates a spend authorization signature over the given message. /// Randomizes this spend authorizing key with the given `randomizer`.
pub fn sign<R: RngCore + CryptoRng>( ///
&self, /// The resulting key can be used to actually sign a spend.
rng: R, pub fn randomize(&self, randomizer: &pallas::Scalar) -> redpallas::SigningKey<SpendAuth> {
msg: &[u8], self.0.randomize(randomizer)
) -> redpallas::Signature<SpendAuth> {
self.0.sign(rng, msg)
} }
} }

View File

@ -40,6 +40,15 @@ impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
} }
} }
impl SigningKey<SpendAuth> {
/// Randomizes this signing key with the given `randomizer`.
///
/// Randomization is only supported for `SpendAuth` keys.
pub fn randomize(&self, randomizer: &pallas::Scalar) -> Self {
SigningKey(self.0.randomize(randomizer))
}
}
impl<T: SigType> SigningKey<T> { impl<T: SigType> SigningKey<T> {
/// Creates a signature of type `T` on `msg` using this `SigningKey`. /// Creates a signature of type `T` on `msg` using this `SigningKey`.
pub fn sign<R: RngCore + CryptoRng>(&self, rng: R, msg: &[u8]) -> Signature<T> { pub fn sign<R: RngCore + CryptoRng>(&self, rng: R, msg: &[u8]) -> Signature<T> {