From 0635192b6b005bf7bd9ba0669b0f412d7451f6c8 Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Sat, 11 Jun 2022 00:14:45 +0300 Subject: [PATCH 1/2] feat: adds fedl vuf --- proof-essentials/Cargo.toml | 1 + proof-essentials/src/error.rs | 3 + proof-essentials/src/lib.rs | 1 + proof-essentials/src/vuf/fedl/mod.rs | 128 ++++++++++++++++++ proof-essentials/src/vuf/fedl/test.rs | 66 +++++++++ proof-essentials/src/vuf/mod.rs | 40 ++++++ .../chaum_pedersen_dl_equality/proof.rs | 2 +- 7 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 proof-essentials/src/vuf/fedl/mod.rs create mode 100644 proof-essentials/src/vuf/fedl/test.rs create mode 100644 proof-essentials/src/vuf/mod.rs diff --git a/proof-essentials/Cargo.toml b/proof-essentials/Cargo.toml index 8a18cc2..a200101 100644 --- a/proof-essentials/Cargo.toml +++ b/proof-essentials/Cargo.toml @@ -16,6 +16,7 @@ starknet-curve = { path = "../starknet-curve" } thiserror = "1.0.30" blake2 = { version = "0.9", default-features = false } digest = { version = "0.9" } +tiny-keccak = { version = "2.0.2", features = [ "shake" ] } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } diff --git a/proof-essentials/src/error.rs b/proof-essentials/src/error.rs index c5cbf5e..526073b 100644 --- a/proof-essentials/src/error.rs +++ b/proof-essentials/src/error.rs @@ -32,6 +32,9 @@ pub enum CryptoError { #[error("IoError: {0}")] IoError(String), + + #[error("Cannot hash to curve")] + CannotHashToCurve, } impl From for CryptoError { diff --git a/proof-essentials/src/lib.rs b/proof-essentials/src/lib.rs index a134f84..a185725 100644 --- a/proof-essentials/src/lib.rs +++ b/proof-essentials/src/lib.rs @@ -2,4 +2,5 @@ pub mod error; pub mod homomorphic_encryption; pub mod utils; pub mod vector_commitment; +pub mod vuf; pub mod zkp; diff --git a/proof-essentials/src/vuf/fedl/mod.rs b/proof-essentials/src/vuf/fedl/mod.rs new file mode 100644 index 0000000..5a30d26 --- /dev/null +++ b/proof-essentials/src/vuf/fedl/mod.rs @@ -0,0 +1,128 @@ +mod test; + +use crate::{ + error::CryptoError, + vuf::VerifiableUnpredictableFunction, + zkp::{ + proofs::chaum_pedersen_dl_equality::{ + proof::Proof, DLEquality, Parameters as ChaumPedersenParameters, Statement, + }, + ArgumentOfKnowledge, + }, +}; +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::UniformRand; +use ark_marlin::rng::FiatShamirRng; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; +use ark_std::{ + io::{Read, Write}, + marker::PhantomData, + rand::Rng, +}; +use blake2::Blake2s; +use tiny_keccak::{Hasher, Shake, Xof}; + +const FS_RNG_SEED: &'static [u8] = b"FEDL"; + +/// Unique signature scheme based on [EDL](with a change to fix the randmoness), with fixed randomness, henced Fixed EDL +pub struct FEDL<'a, C: ProjectiveCurve> { + _group: PhantomData, + _message_lifetime: PhantomData<&'a ()>, +} + +#[derive(Copy, Clone, CanonicalSerialize, CanonicalDeserialize)] +pub struct Parameters { + pub g: C::Affine, +} + +fn try_and_increment(msg: &[u8]) -> Result { + for nonce in 0u8..=255 { + let mut h = Shake::v128(); + h.update(&[nonce]); + h.update(msg.as_ref()); + let output_size = C::zero().serialized_size(); + let mut output = vec![0u8; output_size]; + h.squeeze(&mut output); + + if let Some(p) = C::Affine::from_random_bytes(&output) { + return Ok(p); + } + } + + Err(CryptoError::CannotHashToCurve) +} + +#[derive(Copy, Clone, CanonicalSerialize, CanonicalDeserialize)] +pub struct Signature { + pub proof: Proof, + pub b: C::Affine, +} + +impl<'a, C: ProjectiveCurve> VerifiableUnpredictableFunction for FEDL<'a, C> { + type Message = &'a [u8]; + type Parameters = Parameters; + type PublicKey = ::Affine; + type SecretKey = ::ScalarField; + type Signature = Signature; + type UniqueToken = ::Affine; + + fn keygen( + pp: &Self::Parameters, + rng: &mut R, + ) -> Result<(Self::PublicKey, Self::SecretKey), CryptoError> { + let secret_key = Self::SecretKey::rand(rng).into(); + let public_key = pp.g.mul(secret_key).into(); + Ok((public_key, secret_key)) + } + + fn sign( + pp: &Self::Parameters, + rng: &mut R, + keypair: (&Self::PublicKey, &Self::SecretKey), + message: Self::Message, + ) -> Result { + let hash_of_message: C::Affine = try_and_increment::(message)?; + let chaum_pedersen_parameters = ChaumPedersenParameters { + g: &pp.g, + h: &hash_of_message, + }; + let b = hash_of_message.mul(*keypair.1).into(); + let statement = Statement::new(keypair.0, &b); + + let mut fs_rng = FiatShamirRng::::from_seed(&FS_RNG_SEED); + let proof = DLEquality::prove( + rng, + &chaum_pedersen_parameters, + &statement, + keypair.1, + &mut fs_rng, + )?; + Ok(Signature { proof, b }) + } + + fn extract_token(signature: &Self::Signature) -> Result { + Ok(signature.b) + } + + fn verify( + pp: &Self::Parameters, + pk: &Self::PublicKey, + message: Self::Message, + signature: &Self::Signature, + ) -> Result<(), CryptoError> { + let hash_of_message: C::Affine = try_and_increment::(message)?; + let chaum_pedersen_parameters = ChaumPedersenParameters { + g: &pp.g, + h: &hash_of_message, + }; + + let statement = Statement::new(pk, &signature.b); + let mut fs_rng = FiatShamirRng::::from_seed(&FS_RNG_SEED); + DLEquality::verify( + &chaum_pedersen_parameters, + &statement, + &signature.proof, + &mut fs_rng, + ) + } +} diff --git a/proof-essentials/src/vuf/fedl/test.rs b/proof-essentials/src/vuf/fedl/test.rs new file mode 100644 index 0000000..55fff34 --- /dev/null +++ b/proof-essentials/src/vuf/fedl/test.rs @@ -0,0 +1,66 @@ +#[cfg(test)] +mod test { + + use crate::vuf::{ + fedl::{self, FEDL}, + VerifiableUnpredictableFunction, + }; + use ark_ec::ProjectiveCurve; + use ark_std::{rand::thread_rng, UniformRand}; + use rand::{prelude::ThreadRng, Rng}; + use starknet_curve; + + type AffinePoint = starknet_curve::Affine; + type Curve = starknet_curve::Projective; + type Parameters = fedl::Parameters; + + fn setup(rng: &mut R) -> AffinePoint { + Curve::rand(rng).into_affine() + } + + fn test_template() -> (ThreadRng, AffinePoint) { + let mut rng = thread_rng(); + let g = setup(&mut rng); + + (rng, g) + } + + #[test] + fn test_signing_and_uniqueness() { + let (mut rng, g) = test_template(); + + let pp = Parameters { g }; + + let keypair = FEDL::keygen(&pp, &mut rng).unwrap(); + + let message = b"MESSAGE!!!"; + + let signature = + FEDL::sign(&pp, &mut rng, (&keypair.0, &keypair.1), message.as_slice()).unwrap(); + FEDL::verify(&pp, &keypair.0, message.as_slice(), &signature).unwrap(); + let signature2 = + FEDL::sign(&pp, &mut rng, (&keypair.0, &keypair.1), message.as_slice()).unwrap(); + FEDL::verify(&pp, &keypair.0, message.as_slice(), &signature2).unwrap(); + assert_eq!( + FEDL::extract_token(&signature), + FEDL::extract_token(&signature2), + ); + } + + #[test] + #[should_panic] + fn test_bad_signing() { + let (mut rng, g) = test_template(); + + let pp = Parameters { g }; + + let keypair = FEDL::keygen(&pp, &mut rng).unwrap(); + let keypair2 = FEDL::keygen(&pp, &mut rng).unwrap(); + + let message = b"MESSAGE!!!"; + + let signature = + FEDL::sign(&pp, &mut rng, (&keypair.0, &keypair.1), message.as_slice()).unwrap(); + FEDL::verify(&pp, &keypair2.0, message.as_slice(), &signature).unwrap(); + } +} diff --git a/proof-essentials/src/vuf/mod.rs b/proof-essentials/src/vuf/mod.rs new file mode 100644 index 0000000..04e1c79 --- /dev/null +++ b/proof-essentials/src/vuf/mod.rs @@ -0,0 +1,40 @@ +use crate::error::CryptoError; +use ark_ff::ToBytes; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::rand::Rng; + +pub mod fedl; + +pub trait VerifiableUnpredictableFunction { + type Parameters: CanonicalSerialize + CanonicalDeserialize; + type PublicKey: CanonicalSerialize + CanonicalDeserialize; + type SecretKey: CanonicalSerialize + CanonicalDeserialize; + type Signature: CanonicalSerialize + CanonicalDeserialize; + type UniqueToken: CanonicalSerialize + CanonicalDeserialize; + type Message: ToBytes; + + /// Generate a public key and a private key. + fn keygen( + pp: &Self::Parameters, + rng: &mut R, + ) -> Result<(Self::PublicKey, Self::SecretKey), CryptoError>; + + /// Sign a message. + fn sign( + pp: &Self::Parameters, + rng: &mut R, + keypair: (&Self::PublicKey, &Self::SecretKey), + message: Self::Message, + ) -> Result; + + /// Extract a unique token from a signature. + fn extract_token(signature: &Self::Signature) -> Result; + + /// Verify a signature. + fn verify( + pp: &Self::Parameters, + pk: &Self::PublicKey, + message: Self::Message, + signature: &Self::Signature, + ) -> Result<(), CryptoError>; +} diff --git a/proof-essentials/src/zkp/proofs/chaum_pedersen_dl_equality/proof.rs b/proof-essentials/src/zkp/proofs/chaum_pedersen_dl_equality/proof.rs index 04dd3f2..333e707 100644 --- a/proof-essentials/src/zkp/proofs/chaum_pedersen_dl_equality/proof.rs +++ b/proof-essentials/src/zkp/proofs/chaum_pedersen_dl_equality/proof.rs @@ -10,7 +10,7 @@ use ark_std::io::{Read, Write}; use ark_std::UniformRand; use digest::Digest; -#[derive(CanonicalDeserialize, CanonicalSerialize)] +#[derive(Copy, Clone, CanonicalDeserialize, CanonicalSerialize)] pub struct Proof where C: ProjectiveCurve, From f1fc5ac37cd592a072f77b9f28d660113d75e029 Mon Sep 17 00:00:00 2001 From: Nicolas Mohnblatt Date: Wed, 22 Jun 2022 14:21:12 +0100 Subject: [PATCH 2/2] fix: modulus bits for the scalar field Co-authored-by: Andrija Novakovic --- starknet-curve/src/fields/fr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starknet-curve/src/fields/fr.rs b/starknet-curve/src/fields/fr.rs index 9a3ad56..40f0c0c 100644 --- a/starknet-curve/src/fields/fr.rs +++ b/starknet-curve/src/fields/fr.rs @@ -80,11 +80,11 @@ impl FpParameters for FrParameters { 0x07fffffffffff9b1, ]); - const MODULUS_BITS: u32 = 251; + const MODULUS_BITS: u32 = 252; const CAPACITY: u32 = Self::MODULUS_BITS - 1; - const REPR_SHAVE_BITS: u32 = 5; + const REPR_SHAVE_BITS: u32 = 4; // INV = -q^{-1} (mod 2^64) const INV: u64 = 13504954208620504625;