Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor to use reddsa crate #152

Merged
merged 1 commit into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Entries are listed in reverse chronological order.

## 0.6.0

* Refactor to use `reddsa` (which is a generalization of this crate).
* Remove FROST code. Use The `reddsa` crate directly if you need it.

## 0.5.1

* Remove unneeded `digest` dependency
Expand Down
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ description = "A standalone implementation of the RedJubjub signature scheme."
features = ["nightly"]

[dependencies]
blake2b_simd = "1"
byteorder = "1.4"
jubjub = "0.9"
reddsa = "0.3.0"
rand_core = "0.6"
serde = { version = "1", optional = true, features = ["derive"] }
thiserror = "1.0"
Expand All @@ -28,7 +26,6 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive
[dev-dependencies]
bincode = "1"
criterion = "0.3"
proptest-derive = "0.3"
lazy_static = "1.4"
proptest = "1.0"
rand = "0.8"
Expand Down
152 changes: 9 additions & 143 deletions src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,17 @@
//! and loss of the ability to easily pinpoint failing signatures.
//!

use std::convert::TryFrom;

use jubjub::*;
use rand_core::{CryptoRng, RngCore};

use crate::{private::Sealed, scalar_mul::VartimeMultiscalarMul, *};

// Shim to generate a random 128bit value in a [u64; 4], without
// importing `rand`.
fn gen_128_bits<R: RngCore + CryptoRng>(mut rng: R) -> [u64; 4] {
let mut bytes = [0u64; 4];
bytes[0] = rng.next_u64();
bytes[1] = rng.next_u64();
bytes
}

#[derive(Clone, Debug)]
enum Inner {
SpendAuth {
vk_bytes: VerificationKeyBytes<SpendAuth>,
sig: Signature<SpendAuth>,
c: Scalar,
},
Binding {
vk_bytes: VerificationKeyBytes<Binding>,
sig: Signature<Binding>,
c: Scalar,
},
}
use crate::*;

/// 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.
#[derive(Clone, Debug)]
pub struct Item {
inner: Inner,
}
pub struct Item(reddsa::batch::Item<sapling::SpendAuth, sapling::Binding>);

impl<'msg, M: AsRef<[u8]>>
From<(
Expand All @@ -72,15 +44,7 @@ impl<'msg, M: AsRef<[u8]>>
&'msg M,
),
) -> Self {
// Compute c now to avoid dependency on the msg lifetime.
let c = HStar::default()
.update(&sig.r_bytes[..])
.update(&vk_bytes.bytes[..])
.update(msg)
.finalize();
Self {
inner: Inner::SpendAuth { vk_bytes, sig, c },
}
Self(reddsa::batch::Item::from_spendauth(vk_bytes.0, sig.0, msg))
}
}

Expand All @@ -90,15 +54,7 @@ impl<'msg, M: AsRef<[u8]>> From<(VerificationKeyBytes<Binding>, Signature<Bindin
fn from(
(vk_bytes, sig, msg): (VerificationKeyBytes<Binding>, Signature<Binding>, &'msg M),
) -> Self {
// Compute c now to avoid dependency on the msg lifetime.
let c = HStar::default()
.update(&sig.r_bytes[..])
.update(&vk_bytes.bytes[..])
.update(msg)
.finalize();
Self {
inner: Inner::Binding { vk_bytes, sig, c },
}
Self(reddsa::batch::Item::from_binding(vk_bytes.0, sig.0, msg))
}
}

Expand All @@ -112,23 +68,13 @@ impl Item {
/// the message.
#[allow(non_snake_case)]
pub fn verify_single(self) -> Result<(), Error> {
match self.inner {
Inner::Binding { vk_bytes, sig, c } => VerificationKey::<Binding>::try_from(vk_bytes)
.and_then(|vk| vk.verify_prehashed(&sig, c)),
Inner::SpendAuth { vk_bytes, sig, c } => {
VerificationKey::<SpendAuth>::try_from(vk_bytes)
.and_then(|vk| vk.verify_prehashed(&sig, c))
}
}
self.0.verify_single().map_err(|e| e.into())
}
}

#[derive(Default)]
/// A batch verification context.
pub struct Verifier {
/// Signature data queued for verification.
signatures: Vec<Item>,
}
pub struct Verifier(reddsa::batch::Verifier<sapling::SpendAuth, sapling::Binding>);

impl Verifier {
/// Construct a new batch verifier.
Expand All @@ -138,7 +84,7 @@ impl Verifier {

/// Queue an Item for verification.
pub fn queue<I: Into<Item>>(&mut self, item: I) {
self.signatures.push(item.into());
self.0.queue(item.into().0);
}

/// Perform batch verification, returning `Ok(())` if all signatures were
Expand Down Expand Up @@ -178,87 +124,7 @@ impl Verifier {
///
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#reddsabatchverify
#[allow(non_snake_case)]
pub fn verify<R: RngCore + CryptoRng>(self, mut rng: R) -> Result<(), Error> {
let n = self.signatures.len();

let mut VK_coeffs = Vec::with_capacity(n);
let mut VKs = Vec::with_capacity(n);
let mut R_coeffs = Vec::with_capacity(self.signatures.len());
let mut Rs = Vec::with_capacity(self.signatures.len());
let mut P_spendauth_coeff = Scalar::zero();
let mut P_binding_coeff = Scalar::zero();

for item in self.signatures.iter() {
let (s_bytes, r_bytes, c) = match item.inner {
Inner::SpendAuth { sig, c, .. } => (sig.s_bytes, sig.r_bytes, c),
Inner::Binding { sig, c, .. } => (sig.s_bytes, sig.r_bytes, c),
};

let s = {
// XXX-jubjub: should not use CtOption here
let maybe_scalar = Scalar::from_bytes(&s_bytes);
if maybe_scalar.is_some().into() {
maybe_scalar.unwrap()
} else {
return Err(Error::InvalidSignature);
}
};

let R = {
// XXX-jubjub: should not use CtOption here
// XXX-jubjub: inconsistent ownership in from_bytes
let maybe_point = AffinePoint::from_bytes(r_bytes);
if maybe_point.is_some().into() {
jubjub::ExtendedPoint::from(maybe_point.unwrap())
} else {
return Err(Error::InvalidSignature);
}
};

let VK = match item.inner {
Inner::SpendAuth { vk_bytes, .. } => {
VerificationKey::<SpendAuth>::try_from(vk_bytes.bytes)?.point
}
Inner::Binding { vk_bytes, .. } => {
VerificationKey::<Binding>::try_from(vk_bytes.bytes)?.point
}
};

let z = Scalar::from_raw(gen_128_bits(&mut rng));

let P_coeff = z * s;
match item.inner {
Inner::SpendAuth { .. } => {
P_spendauth_coeff -= P_coeff;
}
Inner::Binding { .. } => {
P_binding_coeff -= P_coeff;
}
};

R_coeffs.push(z);
Rs.push(R);

VK_coeffs.push(Scalar::zero() + (z * c));
VKs.push(VK);
}

use std::iter::once;

let scalars = once(&P_spendauth_coeff)
.chain(once(&P_binding_coeff))
.chain(VK_coeffs.iter())
.chain(R_coeffs.iter());

let basepoints = [SpendAuth::basepoint(), Binding::basepoint()];
let points = basepoints.iter().chain(VKs.iter()).chain(Rs.iter());

let check = ExtendedPoint::vartime_multiscalar_mul(scalars, points);

if check.is_small_order().into() {
Ok(())
} else {
Err(Error::InvalidSignature)
}
pub fn verify<R: RngCore + CryptoRng>(self, rng: R) -> Result<(), Error> {
self.0.verify(rng).map_err(|e| e.into())
}
}
24 changes: 0 additions & 24 deletions src/constants.rs

This file was deleted.

10 changes: 10 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ pub enum Error {
#[error("Invalid signature.")]
InvalidSignature,
}

impl From<reddsa::Error> for Error {
fn from(e: reddsa::Error) -> Self {
match e {
reddsa::Error::MalformedSigningKey => Error::MalformedSigningKey,
reddsa::Error::MalformedVerificationKey => Error::MalformedVerificationKey,
reddsa::Error::InvalidSignature => Error::InvalidSignature,
}
}
}
Loading