Merge pull request #11 from ZcashFoundation/signverify
Implement sign, verify operations.
This commit is contained in:
commit
24d856de2c
|
@ -5,9 +5,13 @@ authors = ["Henry de Valence <hdevalence@hdevalence.ca>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand_core = "0.5"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
blake2b_simd = "0.5"
|
blake2b_simd = "0.5"
|
||||||
jubjub = { git = "https://github.com/zkcrypto/jubjub", rev = "e83f7d2bd136498a27f9d943fea635d8682bf2c6" }
|
jubjub = { git = "https://github.com/zkcrypto/jubjub", rev = "e83f7d2bd136498a27f9d943fea635d8682bf2c6" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rand = "0.7"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
nightly = []
|
nightly = []
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// An error related to RedJubJub signatures.
|
/// An error related to RedJubJub signatures.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// The encoding of a secret key was malformed.
|
/// The encoding of a secret key was malformed.
|
||||||
#[error("Malformed secret key encoding.")]
|
#[error("Malformed secret key encoding.")]
|
||||||
|
@ -9,4 +9,7 @@ pub enum Error {
|
||||||
/// The encoding of a public key was malformed.
|
/// The encoding of a public key was malformed.
|
||||||
#[error("Malformed public key encoding.")]
|
#[error("Malformed public key encoding.")]
|
||||||
MalformedPublicKey,
|
MalformedPublicKey,
|
||||||
|
/// Signature verification failed.
|
||||||
|
#[error("Invalid signature.")]
|
||||||
|
InvalidSignature,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
use blake2b_simd::{Params, State};
|
||||||
|
|
||||||
|
use crate::Scalar;
|
||||||
|
|
||||||
|
/// Provides H^star, the hash-to-scalar function used by RedJubjub.
|
||||||
|
pub struct HStar {
|
||||||
|
state: State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HStar {
|
||||||
|
fn default() -> Self {
|
||||||
|
let state = Params::new()
|
||||||
|
.hash_length(64)
|
||||||
|
.personal(b"Zcash_RedJubjubH")
|
||||||
|
.to_state();
|
||||||
|
Self { state }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HStar {
|
||||||
|
/// Add `data` to the hash, and return `Self` for chaining.
|
||||||
|
pub fn update(mut self, data: &[u8]) -> Self {
|
||||||
|
self.state.update(data);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume `self` to compute the hash output.
|
||||||
|
pub fn finalize(mut self) -> Scalar {
|
||||||
|
Scalar::from_bytes_wide(self.state.finalize().as_array())
|
||||||
|
}
|
||||||
|
}
|
45
src/lib.rs
45
src/lib.rs
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod hash;
|
||||||
mod public_key;
|
mod public_key;
|
||||||
mod secret_key;
|
mod secret_key;
|
||||||
mod signature;
|
mod signature;
|
||||||
|
@ -14,11 +15,14 @@ mod signature;
|
||||||
pub type Randomizer = jubjub::Fr;
|
pub type Randomizer = jubjub::Fr;
|
||||||
|
|
||||||
/// A better name than Fr.
|
/// A better name than Fr.
|
||||||
|
// XXX-jubjub: upstream this name
|
||||||
type Scalar = jubjub::Fr;
|
type Scalar = jubjub::Fr;
|
||||||
|
|
||||||
|
use hash::HStar;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use public_key::{PublicKey, PublicKeyBytes};
|
pub use public_key::{PublicKey, PublicKeyBytes};
|
||||||
pub use secret_key::{SecretKey, SecretKeyBytes};
|
pub use secret_key::SecretKey;
|
||||||
pub use signature::Signature;
|
pub use signature::Signature;
|
||||||
|
|
||||||
/// Abstracts over different RedJubJub parameter choices.
|
/// Abstracts over different RedJubJub parameter choices.
|
||||||
|
@ -35,16 +39,47 @@ pub use signature::Signature;
|
||||||
pub trait SigType: private::Sealed {}
|
pub trait SigType: private::Sealed {}
|
||||||
|
|
||||||
/// A type variable corresponding to Zcash's `BindingSig`.
|
/// A type variable corresponding to Zcash's `BindingSig`.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Binding {}
|
pub struct Binding {}
|
||||||
impl SigType for Binding {}
|
impl SigType for Binding {}
|
||||||
|
|
||||||
/// A type variable corresponding to Zcash's `SpendAuthSig`.
|
/// A type variable corresponding to Zcash's `SpendAuthSig`.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SpendAuth {}
|
pub struct SpendAuth {}
|
||||||
impl SigType for SpendAuth {}
|
impl SigType for SpendAuth {}
|
||||||
|
|
||||||
mod private {
|
pub(crate) mod private {
|
||||||
use super::*;
|
use super::*;
|
||||||
pub trait Sealed {}
|
pub trait Sealed: Copy + Clone + std::fmt::Debug {
|
||||||
impl Sealed for Binding {}
|
fn basepoint() -> jubjub::ExtendedPoint;
|
||||||
impl Sealed for SpendAuth {}
|
}
|
||||||
|
impl Sealed for Binding {
|
||||||
|
fn basepoint() -> jubjub::ExtendedPoint {
|
||||||
|
jubjub::AffinePoint::from_bytes(constants::BINDINGSIG_BASEPOINT_BYTES)
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Sealed for SpendAuth {
|
||||||
|
fn basepoint() -> jubjub::ExtendedPoint {
|
||||||
|
jubjub::AffinePoint::from_bytes(constants::SPENDAUTHSIG_BASEPOINT_BYTES)
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign_and_verify() {
|
||||||
|
let sk = SecretKey::<Binding>::new(rand::thread_rng());
|
||||||
|
let msg = b"test";
|
||||||
|
let sig = sk.sign(rand::thread_rng(), msg);
|
||||||
|
let pk = PublicKey::from(&sk);
|
||||||
|
|
||||||
|
assert_eq!(pk.verify(msg, &sig), Ok(()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
use std::{convert::TryFrom, marker::PhantomData};
|
use std::{convert::TryFrom, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{Binding, Error, Randomizer, SigType, Signature, SpendAuth};
|
use crate::{Binding, Error, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
||||||
|
|
||||||
/// A refinement type indicating that the inner `[u8; 32]` represents an
|
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
||||||
/// encoding of a RedJubJub public key.
|
/// an encoding of a RedJubJub public key.
|
||||||
|
///
|
||||||
|
/// This is useful for representing a compressed public key; the
|
||||||
|
/// [`PublicKey`] type in this library holds other decompressed state
|
||||||
|
/// used in signature verification.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct PublicKeyBytes<T: SigType> {
|
pub struct PublicKeyBytes<T: SigType> {
|
||||||
bytes: [u8; 32],
|
pub(crate) bytes: [u8; 32],
|
||||||
_marker: PhantomData<T>,
|
pub(crate) _marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<[u8; 32]> for PublicKeyBytes<T> {
|
impl<T: SigType> From<[u8; 32]> for PublicKeyBytes<T> {
|
||||||
|
@ -26,20 +30,16 @@ impl<T: SigType> From<PublicKeyBytes<T>> for [u8; 32] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A RedJubJub public key.
|
/// A RedJubJub public key.
|
||||||
// XXX PartialEq, Eq?
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct PublicKey<T: SigType> {
|
pub struct PublicKey<T: SigType> {
|
||||||
// XXX-jubjub: this should just be Point
|
// XXX-jubjub: this should just be Point
|
||||||
pub(crate) point: jubjub::ExtendedPoint,
|
pub(crate) point: jubjub::ExtendedPoint,
|
||||||
// XXX should this just store a PublicKeyBytes?
|
pub(crate) bytes: PublicKeyBytes<T>,
|
||||||
pub(crate) bytes: [u8; 32],
|
|
||||||
pub(crate) _marker: PhantomData<T>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<PublicKey<T>> for PublicKeyBytes<T> {
|
impl<T: SigType> From<PublicKey<T>> for PublicKeyBytes<T> {
|
||||||
fn from(pk: PublicKey<T>) -> PublicKeyBytes<T> {
|
fn from(pk: PublicKey<T>) -> PublicKeyBytes<T> {
|
||||||
let PublicKey { bytes, _marker, .. } = pk;
|
pk.bytes
|
||||||
PublicKeyBytes { bytes, _marker }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,7 @@ impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
|
||||||
if maybe_point.is_some().into() {
|
if maybe_point.is_some().into() {
|
||||||
Ok(PublicKey {
|
Ok(PublicKey {
|
||||||
point: maybe_point.unwrap().into(),
|
point: maybe_point.unwrap().into(),
|
||||||
bytes: bytes.bytes,
|
bytes,
|
||||||
_marker: PhantomData,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::MalformedPublicKey)
|
Err(Error::MalformedPublicKey)
|
||||||
|
@ -63,26 +62,63 @@ impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> PublicKey<T> {
|
impl<T: SigType> PublicKey<T> {
|
||||||
|
pub(crate) fn from_secret(s: &Scalar) -> PublicKey<T> {
|
||||||
|
let point = &T::basepoint() * s;
|
||||||
|
let bytes = PublicKeyBytes {
|
||||||
|
bytes: jubjub::AffinePoint::from(&point).to_bytes(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
PublicKey { bytes, point }
|
||||||
|
}
|
||||||
|
|
||||||
/// Randomize this public key with the given `randomizer`.
|
/// Randomize this public key with the given `randomizer`.
|
||||||
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl PublicKey<Binding> {
|
/// Verify a purported `signature` over `msg` made by this public key.
|
||||||
/// Verify a Zcash `BindingSig` 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<Binding>) -> Result<(), Error> {
|
pub fn verify(&self, msg: &[u8], signature: &Signature<Binding>) -> Result<(), Error> {
|
||||||
// this lets us specialize the basepoint parameter, could call a verify_inner
|
use crate::HStar;
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PublicKey<SpendAuth> {
|
let r = {
|
||||||
/// Verify a Zcash `SpendAuthSig` over `msg` made by this public key.
|
// XXX-jubjub: should not use CtOption here
|
||||||
// This is similar to impl signature::Verifier but without boxed errors
|
// XXX-jubjub: inconsistent ownership in from_bytes
|
||||||
pub fn verify(&self, msg: &[u8], signature: &Signature<SpendAuth>) -> Result<(), Error> {
|
let maybe_point = jubjub::AffinePoint::from_bytes(signature.r_bytes);
|
||||||
// this lets us specialize the basepoint parameter, could call a verify_inner
|
if maybe_point.is_some().into() {
|
||||||
unimplemented!();
|
jubjub::ExtendedPoint::from(maybe_point.unwrap())
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvalidSignature);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let s = {
|
||||||
|
// XXX-jubjub: should not use CtOption here
|
||||||
|
let maybe_scalar = Scalar::from_bytes(&signature.s_bytes);
|
||||||
|
if maybe_scalar.is_some().into() {
|
||||||
|
maybe_scalar.unwrap()
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvalidSignature);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let c = HStar::default()
|
||||||
|
.update(&signature.r_bytes[..])
|
||||||
|
.update(&self.bytes.bytes[..]) // XXX ugly
|
||||||
|
.update(msg)
|
||||||
|
.finalize();
|
||||||
|
|
||||||
|
// XXX rewrite as normal double scalar mul
|
||||||
|
// Verify check is h * ( - s * B + R + c * A) == 0
|
||||||
|
// h * ( s * B - c * A - R) == 0
|
||||||
|
let sB = &T::basepoint() * &s;
|
||||||
|
let cA = &self.point * &c;
|
||||||
|
let check = sB - cA - r;
|
||||||
|
|
||||||
|
if check.is_small_order().into() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidSignature)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,124 +1,94 @@
|
||||||
use std::{convert::TryFrom, marker::PhantomData};
|
use std::{convert::TryFrom, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{Binding, Error, PublicKey, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
use crate::{
|
||||||
|
Binding, Error, PublicKey, PublicKeyBytes, Randomizer, Scalar, SigType, Signature, SpendAuth,
|
||||||
|
};
|
||||||
|
|
||||||
/// A refinement type indicating that the inner `[u8; 32]` represents an
|
use rand_core::{CryptoRng, RngCore};
|
||||||
/// encoding of a RedJubJub secret key.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct SecretKeyBytes<T: SigType> {
|
|
||||||
bytes: [u8; 32],
|
|
||||||
_marker: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SigType> From<[u8; 32]> for SecretKeyBytes<T> {
|
|
||||||
fn from(bytes: [u8; 32]) -> SecretKeyBytes<T> {
|
|
||||||
SecretKeyBytes {
|
|
||||||
bytes,
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SigType> From<SecretKeyBytes<T>> for [u8; 32] {
|
|
||||||
fn from(refined: SecretKeyBytes<T>) -> [u8; 32] {
|
|
||||||
refined.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A RedJubJub secret key.
|
/// A RedJubJub secret key.
|
||||||
// XXX PartialEq, Eq?
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SecretKey<T: SigType> {
|
pub struct SecretKey<T: SigType> {
|
||||||
sk: Scalar,
|
sk: Scalar,
|
||||||
_marker: PhantomData<T>,
|
pk: PublicKey<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<SecretKey<T>> for SecretKeyBytes<T> {
|
impl<'a, T: SigType> From<&'a SecretKey<T>> for PublicKey<T> {
|
||||||
fn from(sk: SecretKey<T>) -> SecretKeyBytes<T> {
|
fn from(sk: &'a SecretKey<T>) -> PublicKey<T> {
|
||||||
SecretKeyBytes {
|
sk.pk.clone()
|
||||||
bytes: sk.sk.to_bytes(),
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX could this be a From impl?
|
impl<T: SigType> From<SecretKey<T>> for [u8; 32] {
|
||||||
// not unless there's an infallible conversion from bytes to scalars,
|
fn from(sk: SecretKey<T>) -> [u8; 32] {
|
||||||
// which is not currently present in jubjub
|
sk.sk.to_bytes()
|
||||||
impl<T: SigType> TryFrom<SecretKeyBytes<T>> for SecretKey<T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(bytes: SecretKeyBytes<T>) -> Result<Self, Self::Error> {
|
|
||||||
// XXX-jubjub: it does not make sense for this to be a CtOption...
|
|
||||||
// XXX-jubjub: this takes a borrow but point deser doesn't
|
|
||||||
let maybe_sk = Scalar::from_bytes(&bytes.bytes);
|
|
||||||
if maybe_sk.is_some().into() {
|
|
||||||
Ok(SecretKey {
|
|
||||||
sk: maybe_sk.unwrap(),
|
|
||||||
_marker: PhantomData,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::MalformedSecretKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a SecretKey<SpendAuth>> for PublicKey<SpendAuth> {
|
impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
|
||||||
fn from(sk: &'a SecretKey<SpendAuth>) -> PublicKey<SpendAuth> {
|
fn from(bytes: [u8; 32]) -> Self {
|
||||||
// XXX-jubjub: this is pretty baroque
|
let sk = {
|
||||||
// XXX-jubjub: provide basepoint tables for generators
|
// XXX-jubjub: would be nice to unconditionally deser
|
||||||
let basepoint: jubjub::ExtendedPoint =
|
// This incantation ensures deserialization is infallible.
|
||||||
jubjub::AffinePoint::from_bytes(crate::constants::SPENDAUTHSIG_BASEPOINT_BYTES)
|
let mut wide = [0; 64];
|
||||||
.unwrap()
|
wide[0..32].copy_from_slice(&bytes);
|
||||||
.into();
|
Scalar::from_bytes_wide(&wide)
|
||||||
pk_from_sk_inner(sk, basepoint)
|
};
|
||||||
}
|
let pk = PublicKey::from_secret(&sk);
|
||||||
}
|
SecretKey { sk, pk }
|
||||||
|
|
||||||
impl<'a> From<&'a SecretKey<Binding>> for PublicKey<Binding> {
|
|
||||||
fn from(sk: &'a SecretKey<Binding>) -> PublicKey<Binding> {
|
|
||||||
let basepoint: jubjub::ExtendedPoint =
|
|
||||||
jubjub::AffinePoint::from_bytes(crate::constants::BINDINGSIG_BASEPOINT_BYTES)
|
|
||||||
.unwrap()
|
|
||||||
.into();
|
|
||||||
pk_from_sk_inner(sk, basepoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pk_from_sk_inner<T: SigType>(
|
|
||||||
sk: &SecretKey<T>,
|
|
||||||
basepoint: jubjub::ExtendedPoint,
|
|
||||||
) -> PublicKey<T> {
|
|
||||||
let point = &basepoint * &sk.sk;
|
|
||||||
let bytes = jubjub::AffinePoint::from(&point).to_bytes();
|
|
||||||
PublicKey {
|
|
||||||
point,
|
|
||||||
bytes,
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> SecretKey<T> {
|
impl<T: SigType> SecretKey<T> {
|
||||||
|
/// Generate a new secret key.
|
||||||
|
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SecretKey<T> {
|
||||||
|
let sk = {
|
||||||
|
let mut bytes = [0; 64];
|
||||||
|
rng.fill_bytes(&mut bytes);
|
||||||
|
Scalar::from_bytes_wide(&bytes)
|
||||||
|
};
|
||||||
|
let pk = PublicKey::from_secret(&sk);
|
||||||
|
SecretKey { sk, pk }
|
||||||
|
}
|
||||||
|
|
||||||
/// Randomize this public key with the given `randomizer`.
|
/// Randomize this public key with the given `randomizer`.
|
||||||
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl SecretKey<Binding> {
|
/// Create a signature of type `T` on `msg` using this `SecretKey`.
|
||||||
/// Create a Zcash `BindingSig` on `msg` using this `SecretKey`.
|
|
||||||
// Similar to signature::Signer but without boxed errors.
|
// Similar to signature::Signer but without boxed errors.
|
||||||
pub fn sign(&self, msg: &[u8]) -> Signature<Binding> {
|
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
|
||||||
// could use sign_inner
|
use crate::HStar;
|
||||||
unimplemented!();
|
|
||||||
}
|
// Choose a byte sequence uniformly at random of length
|
||||||
}
|
// (\ell_H + 128)/8 bytes. For RedJubjub this is (512 + 128)/8 = 80.
|
||||||
|
let random_bytes = {
|
||||||
impl SecretKey<SpendAuth> {
|
let mut bytes = [0; 80];
|
||||||
/// Create a Zcash `SpendAuthSig` on `msg` using this `SecretKey`.
|
rng.fill_bytes(&mut bytes);
|
||||||
// Similar to signature::Signer but without boxed errors.
|
bytes
|
||||||
pub fn sign(&self, msg: &[u8]) -> Signature<SpendAuth> {
|
};
|
||||||
// could use sign_inner
|
|
||||||
unimplemented!();
|
let nonce = HStar::default()
|
||||||
|
.update(&random_bytes[..])
|
||||||
|
.update(&self.pk.bytes.bytes[..]) // XXX ugly
|
||||||
|
.update(msg)
|
||||||
|
.finalize();
|
||||||
|
|
||||||
|
let r_bytes = jubjub::AffinePoint::from(&T::basepoint() * &nonce).to_bytes();
|
||||||
|
|
||||||
|
let c = HStar::default()
|
||||||
|
.update(&r_bytes[..])
|
||||||
|
.update(&self.pk.bytes.bytes[..]) // XXX ugly
|
||||||
|
.update(msg)
|
||||||
|
.finalize();
|
||||||
|
|
||||||
|
let s_bytes = (&nonce + &(&c * &self.sk)).to_bytes();
|
||||||
|
|
||||||
|
Signature {
|
||||||
|
r_bytes,
|
||||||
|
s_bytes,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,53 +3,32 @@ use std::{convert, fmt, marker::PhantomData};
|
||||||
use crate::SigType;
|
use crate::SigType;
|
||||||
|
|
||||||
/// A RedJubJub signature.
|
/// A RedJubJub signature.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Signature<T: SigType> {
|
pub struct Signature<T: SigType> {
|
||||||
bytes: [u8; 64],
|
pub(crate) r_bytes: [u8; 32],
|
||||||
_marker: PhantomData<T>,
|
pub(crate) s_bytes: [u8; 32],
|
||||||
|
pub(crate) _marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<[u8; 64]> for Signature<T> {
|
impl<T: SigType> From<[u8; 64]> for Signature<T> {
|
||||||
fn from(bytes: [u8; 64]) -> Signature<T> {
|
fn from(bytes: [u8; 64]) -> Signature<T> {
|
||||||
|
let mut r_bytes = [0; 32];
|
||||||
|
r_bytes.copy_from_slice(&bytes[0..32]);
|
||||||
|
let mut s_bytes = [0; 32];
|
||||||
|
s_bytes.copy_from_slice(&bytes[32..64]);
|
||||||
Signature {
|
Signature {
|
||||||
bytes,
|
r_bytes,
|
||||||
|
s_bytes,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<Signature<T>> for [u8; 64] {
|
impl<T: SigType> From<Signature<T>> for [u8; 64] {
|
||||||
fn from(s: Signature<T>) -> [u8; 64] {
|
fn from(sig: Signature<T>) -> [u8; 64] {
|
||||||
s.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These impls all only exist because of array length restrictions.
|
|
||||||
|
|
||||||
// XXX print the type variable
|
|
||||||
impl<T: SigType> fmt::Debug for Signature<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
//f.debug_tuple("Signature").field(&self.0[..]).finish()
|
|
||||||
f.debug_tuple("Signature").finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SigType> Copy for Signature<T> {}
|
|
||||||
|
|
||||||
impl<T: SigType> Clone for Signature<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut bytes = [0; 64];
|
let mut bytes = [0; 64];
|
||||||
bytes[..].copy_from_slice(&self.bytes[..]);
|
bytes[0..32].copy_from_slice(&sig.r_bytes[..]);
|
||||||
Signature {
|
bytes[32..64].copy_from_slice(&sig.s_bytes[..]);
|
||||||
bytes,
|
bytes
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> PartialEq for Signature<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.bytes[..] == other.bytes[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SigType> Eq for Signature<T> {}
|
|
||||||
|
|
Loading…
Reference in New Issue