Initial commit to extract crypto-primitives to new crate

This commit is contained in:
Pratyush Mishra
2019-09-24 20:21:49 -07:00
parent 5a78e24e15
commit a244e719d1
33 changed files with 4746 additions and 1 deletions

View File

@@ -0,0 +1,18 @@
use algebra::Field;
use r1cs_core::{ConstraintSystem, SynthesisError};
use r1cs_std::prelude::*;
use crate::signature::SignatureScheme;
pub trait SigRandomizePkGadget<S: SignatureScheme, ConstraintF: Field> {
type ParametersGadget: AllocGadget<S::Parameters, ConstraintF> + Clone;
type PublicKeyGadget: ToBytesGadget<ConstraintF> + EqGadget<ConstraintF> + AllocGadget<S::PublicKey, ConstraintF> + Clone;
fn check_randomization_gadget<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
parameters: &Self::ParametersGadget,
public_key: &Self::PublicKeyGadget,
randomness: &[UInt8],
) -> Result<Self::PublicKeyGadget, SynthesisError>;
}

View File

@@ -0,0 +1,106 @@
use algebra::bytes::ToBytes;
use crate::Error;
use rand::Rng;
use std::hash::Hash;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
pub mod schnorr;
pub trait SignatureScheme {
type Parameters: Clone + Send + Sync;
type PublicKey: ToBytes + Hash + Eq + Clone + Default + Send + Sync;
type SecretKey: ToBytes + Clone + Default;
type Signature: Clone + Default + Send + Sync;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error>;
fn keygen<R: Rng>(
pp: &Self::Parameters,
rng: &mut R,
) -> Result<(Self::PublicKey, Self::SecretKey), Error>;
fn sign<R: Rng>(
pp: &Self::Parameters,
sk: &Self::SecretKey,
message: &[u8],
rng: &mut R,
) -> Result<Self::Signature, Error>;
fn verify(
pp: &Self::Parameters,
pk: &Self::PublicKey,
message: &[u8],
signature: &Self::Signature,
) -> Result<bool, Error>;
fn randomize_public_key(
pp: &Self::Parameters,
public_key: &Self::PublicKey,
randomness: &[u8],
) -> Result<Self::PublicKey, Error>;
fn randomize_signature(
pp: &Self::Parameters,
signature: &Self::Signature,
randomness: &[u8],
) -> Result<Self::Signature, Error>;
}
#[cfg(test)]
mod test {
use crate::{signature::schnorr::SchnorrSignature, SignatureScheme};
use algebra::{
curves::edwards_sw6::EdwardsAffine as Edwards, groups::Group, to_bytes, ToBytes,
};
use blake2::Blake2s;
use rand::thread_rng;
use algebra::UniformRand;
fn sign_and_verify<S: SignatureScheme>(message: &[u8]) {
let rng = &mut thread_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, &message, rng).unwrap();
assert!(S::verify(&parameters, &pk, &message, &sig).unwrap());
}
fn failed_verification<S: SignatureScheme>(message: &[u8], bad_message: &[u8]) {
let rng = &mut thread_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, message, rng).unwrap();
assert!(!S::verify(&parameters, &pk, bad_message, &sig).unwrap());
}
fn randomize_and_verify<S: SignatureScheme>(message: &[u8], randomness: &[u8]) {
let rng = &mut thread_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, message, rng).unwrap();
assert!(S::verify(&parameters, &pk, message, &sig).unwrap());
let randomized_pk = S::randomize_public_key(&parameters, &pk, randomness).unwrap();
let randomized_sig = S::randomize_signature(&parameters, &sig, randomness).unwrap();
assert!(S::verify(&parameters, &randomized_pk, &message, &randomized_sig).unwrap());
}
#[test]
fn schnorr_signature_test() {
let message = "Hi, I am a Schnorr signature!";
let rng = &mut thread_rng();
sign_and_verify::<SchnorrSignature<Edwards, Blake2s>>(message.as_bytes());
failed_verification::<SchnorrSignature<Edwards, Blake2s>>(
message.as_bytes(),
"Bad message".as_bytes(),
);
let random_scalar = to_bytes!(<Edwards as Group>::ScalarField::rand(rng)).unwrap();
randomize_and_verify::<SchnorrSignature<Edwards, Blake2s>>(
message.as_bytes(),
&random_scalar.as_slice(),
);
}
}

View File

@@ -0,0 +1,210 @@
use algebra::{groups::Group, Field};
use r1cs_core::{ConstraintSystem, SynthesisError};
use r1cs_std::prelude::*;
use crate::signature::SigRandomizePkGadget;
use std::{borrow::Borrow, marker::PhantomData};
use crate::signature::schnorr::{
SchnorrPublicKey, SchnorrSigParameters, SchnorrSignature,
};
use digest::Digest;
pub struct SchnorrSigGadgetParameters<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> {
generator: GG,
_group: PhantomData<*const G>,
_engine: PhantomData<*const ConstraintF>,
}
impl<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> Clone
for SchnorrSigGadgetParameters<G, ConstraintF, GG>
{
fn clone(&self) -> Self {
Self {
generator: self.generator.clone(),
_group: PhantomData,
_engine: PhantomData,
}
}
}
#[derive(Derivative)]
#[derivative(
Debug(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"),
Clone(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"),
PartialEq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"),
Eq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>")
)]
pub struct SchnorrSigGadgetPk<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> {
pub_key: GG,
#[doc(hidden)]
_group: PhantomData<*const G>,
#[doc(hidden)]
_engine: PhantomData<*const ConstraintF>,
}
pub struct SchnorrRandomizePkGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> {
#[doc(hidden)]
_group: PhantomData<*const G>,
#[doc(hidden)]
_group_gadget: PhantomData<*const GG>,
#[doc(hidden)]
_engine: PhantomData<*const ConstraintF>,
}
impl<G, GG, D, ConstraintF> SigRandomizePkGadget<SchnorrSignature<G, D>, ConstraintF>
for SchnorrRandomizePkGadget<G, ConstraintF, GG>
where
G: Group,
GG: GroupGadget<G, ConstraintF>,
D: Digest + Send + Sync,
ConstraintF: Field,
{
type ParametersGadget = SchnorrSigGadgetParameters<G, ConstraintF, GG>;
type PublicKeyGadget = SchnorrSigGadgetPk<G, ConstraintF, GG>;
fn check_randomization_gadget<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
parameters: &Self::ParametersGadget,
public_key: &Self::PublicKeyGadget,
randomness: &[UInt8],
) -> Result<Self::PublicKeyGadget, SynthesisError> {
let base = parameters.generator.clone();
let randomness = randomness
.iter()
.flat_map(|b| b.into_bits_le())
.collect::<Vec<_>>();
let rand_pk = base.mul_bits(
&mut cs.ns(|| "Compute Randomizer"),
&public_key.pub_key,
randomness.iter(),
)?;
Ok(SchnorrSigGadgetPk {
pub_key: rand_pk,
_group: PhantomData,
_engine: PhantomData,
})
}
}
impl<G, ConstraintF, GG, D> AllocGadget<SchnorrSigParameters<G, D>, ConstraintF>
for SchnorrSigGadgetParameters<G, ConstraintF, GG>
where
G: Group,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
D: Digest,
{
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<SchnorrSigParameters<G, D>>,
{
let generator = GG::alloc_checked(cs, || f().map(|pp| pp.borrow().generator))?;
Ok(Self {
generator,
_engine: PhantomData,
_group: PhantomData,
})
}
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<SchnorrSigParameters<G, D>>,
{
let generator = GG::alloc_input(cs, || f().map(|pp| pp.borrow().generator))?;
Ok(Self {
generator,
_engine: PhantomData,
_group: PhantomData,
})
}
}
impl<G, ConstraintF, GG> AllocGadget<SchnorrPublicKey<G>, ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG>
where
G: Group,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
{
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<SchnorrPublicKey<G>>,
{
let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?;
Ok(Self {
pub_key,
_engine: PhantomData,
_group: PhantomData,
})
}
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<SchnorrPublicKey<G>>,
{
let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?;
Ok(Self {
pub_key,
_engine: PhantomData,
_group: PhantomData,
})
}
}
impl<G, ConstraintF, GG> ConditionalEqGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG>
where
G: Group,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
{
#[inline]
fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
&self,
mut cs: CS,
other: &Self,
condition: &Boolean,
) -> Result<(), SynthesisError> {
self.pub_key.conditional_enforce_equal(
&mut cs.ns(|| "PubKey equality"),
&other.pub_key,
condition,
)?;
Ok(())
}
fn cost() -> usize {
<GG as ConditionalEqGadget<ConstraintF>>::cost()
}
}
impl<G, ConstraintF, GG> EqGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG>
where
G: Group,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
{
}
impl<G, ConstraintF, GG> ToBytesGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG>
where
G: Group,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
{
fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> {
self.pub_key.to_bytes(&mut cs.ns(|| "PubKey To Bytes"))
}
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
mut cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.pub_key
.to_bytes_strict(&mut cs.ns(|| "PubKey To Bytes"))
}
}

View File

@@ -0,0 +1,223 @@
use crate::SignatureScheme;
use algebra::{
bytes::ToBytes,
fields::{Field, PrimeField},
groups::Group,
to_bytes,
};
use digest::Digest;
use crate::Error;
use algebra::UniformRand;
use rand::Rng;
use std::{
hash::Hash,
io::{Result as IoResult, Write},
marker::PhantomData,
};
#[cfg(feature = "r1cs")]
pub mod constraints;
pub struct SchnorrSignature<G: Group, D: Digest> {
_group: PhantomData<G>,
_hash: PhantomData<D>,
}
#[derive(Derivative)]
#[derivative(Clone(bound = "G: Group, H: Digest"))]
pub struct SchnorrSigParameters<G: Group, H: Digest> {
_hash: PhantomData<H>,
pub generator: G,
pub salt: [u8; 32],
}
pub type SchnorrPublicKey<G> = G;
#[derive(Derivative)]
#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))]
pub struct SchnorrSecretKey<G: Group>(pub G::ScalarField);
impl<G: Group> ToBytes for SchnorrSecretKey<G> {
#[inline]
fn write<W: Write>(&self, writer: W) -> IoResult<()> {
self.0.write(writer)
}
}
#[derive(Derivative)]
#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))]
pub struct SchnorrSig<G: Group> {
pub prover_response: G::ScalarField,
pub verifier_challenge: G::ScalarField,
}
impl<G: Group + Hash, D: Digest + Send + Sync> SignatureScheme for SchnorrSignature<G, D>
where
G::ScalarField: PrimeField,
{
type Parameters = SchnorrSigParameters<G, D>;
type PublicKey = G;
type SecretKey = SchnorrSecretKey<G>;
type Signature = SchnorrSig<G>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let setup_time = start_timer!(|| "SchnorrSig::Setup");
let mut salt = [0u8; 32];
rng.fill_bytes(&mut salt);
let generator = G::rand(rng);
end_timer!(setup_time);
Ok(SchnorrSigParameters {
_hash: PhantomData,
generator,
salt,
})
}
fn keygen<R: Rng>(
parameters: &Self::Parameters,
rng: &mut R,
) -> Result<(Self::PublicKey, Self::SecretKey), Error> {
let keygen_time = start_timer!(|| "SchnorrSig::KeyGen");
let secret_key = G::ScalarField::rand(rng);
let public_key = parameters.generator.mul(&secret_key);
end_timer!(keygen_time);
Ok((public_key, SchnorrSecretKey(secret_key)))
}
fn sign<R: Rng>(
parameters: &Self::Parameters,
sk: &Self::SecretKey,
message: &[u8],
rng: &mut R,
) -> Result<Self::Signature, Error> {
let sign_time = start_timer!(|| "SchnorrSig::Sign");
// (k, e);
let (random_scalar, verifier_challenge) = loop {
// Sample a random scalar `k` from the prime scalar field.
let random_scalar: G::ScalarField = G::ScalarField::rand(rng);
// Commit to the random scalar via r := k · g.
// This is the prover's first msg in the Sigma protocol.
let prover_commitment: G = parameters.generator.mul(&random_scalar);
// Hash everything to get verifier challenge.
let mut hash_input = Vec::new();
hash_input.extend_from_slice(&parameters.salt);
hash_input.extend_from_slice(&to_bytes![prover_commitment]?);
hash_input.extend_from_slice(message);
// Compute the supposed verifier response: e := H(salt || r || msg);
if let Some(verifier_challenge) =
G::ScalarField::from_random_bytes(&D::digest(&hash_input))
{
break (random_scalar, verifier_challenge);
};
};
// k - xe;
let prover_response = random_scalar - &(verifier_challenge * &sk.0);
let signature = SchnorrSig {
prover_response,
verifier_challenge,
};
end_timer!(sign_time);
Ok(signature)
}
fn verify(
parameters: &Self::Parameters,
pk: &Self::PublicKey,
message: &[u8],
signature: &Self::Signature,
) -> Result<bool, Error> {
let verify_time = start_timer!(|| "SchnorrSig::Verify");
let SchnorrSig {
prover_response,
verifier_challenge,
} = signature;
let mut claimed_prover_commitment = parameters.generator.mul(prover_response);
let public_key_times_verifier_challenge = pk.mul(verifier_challenge);
claimed_prover_commitment += &public_key_times_verifier_challenge;
let mut hash_input = Vec::new();
hash_input.extend_from_slice(&parameters.salt);
hash_input.extend_from_slice(&to_bytes![claimed_prover_commitment]?);
hash_input.extend_from_slice(&message);
let obtained_verifier_challenge = if let Some(obtained_verifier_challenge) =
G::ScalarField::from_random_bytes(&D::digest(&hash_input))
{
obtained_verifier_challenge
} else {
return Ok(false);
};
end_timer!(verify_time);
Ok(verifier_challenge == &obtained_verifier_challenge)
}
fn randomize_public_key(
parameters: &Self::Parameters,
public_key: &Self::PublicKey,
randomness: &[u8],
) -> Result<Self::PublicKey, Error> {
let rand_pk_time = start_timer!(|| "SchnorrSig::RandomizePubKey");
let mut randomized_pk = *public_key;
let mut base = parameters.generator;
let mut encoded = G::zero();
for bit in bytes_to_bits(randomness) {
if bit {
encoded += &base;
}
base.double_in_place();
}
randomized_pk += &encoded;
end_timer!(rand_pk_time);
Ok(randomized_pk)
}
fn randomize_signature(
_parameter: &Self::Parameters,
signature: &Self::Signature,
randomness: &[u8],
) -> Result<Self::Signature, Error> {
let rand_signature_time = start_timer!(|| "SchnorrSig::RandomizeSig");
let SchnorrSig {
prover_response,
verifier_challenge,
} = signature;
let mut base = G::ScalarField::one();
let mut multiplier = G::ScalarField::zero();
for bit in bytes_to_bits(randomness) {
if bit {
multiplier += &base;
}
base.double_in_place();
}
let new_sig = SchnorrSig {
prover_response: *prover_response - &(*verifier_challenge * &multiplier),
verifier_challenge: *verifier_challenge,
};
end_timer!(rand_signature_time);
Ok(new_sig)
}
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
let mut bits = Vec::with_capacity(bytes.len() * 8);
for byte in bytes {
for i in 0..8 {
let bit = (*byte >> (8 - i - 1)) & 1;
bits.push(bit == 1);
}
}
bits
}