mirror of
https://github.com/plume-sig/zk-nullifier-sig.git
synced 2026-01-10 13:28:07 -05:00
* Sane error handling and some simplification (ditch unwrap) * excessive code and entities were removed
This commit is contained in:
@@ -1,11 +1,26 @@
|
||||
use thiserror::Error;
|
||||
// Legacy definitions for errors which will be gone with arkworks upgrade to `>=0.4.0`.
|
||||
// `use ark_ec::hashing::HashToCurveError;`
|
||||
|
||||
// use thiserror::Error;
|
||||
|
||||
/// This is an error that could occur when running a cryptograhic primitive
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum CryptoError {
|
||||
#[error("Cannot hash to curve")]
|
||||
CannotHashToCurve,
|
||||
// #[derive(Error, Debug, PartialEq)]
|
||||
// pub enum CryptoError {
|
||||
// #[error("Cannot hash to curve")]
|
||||
// CannotHashToCurve,
|
||||
|
||||
#[error("Cannot encode a point not on the curve")]
|
||||
PointNotOnCurve,
|
||||
// #[error("Cannot encode a point not on the curve")]
|
||||
// PointNotOnCurve,
|
||||
// }
|
||||
|
||||
// Let's outline what errors will be in `~0.4.0`
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HashToCurveError {
|
||||
UnsupportedCurveError(String),
|
||||
MapToCurveError(String),
|
||||
/* let's add two more items to absorb everything
|
||||
in `crate::hash_to_curve` which is
|
||||
subject to deprecation */
|
||||
Legacy,
|
||||
ReferenceTryAndIncrement,
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
use crate::error::CryptoError;
|
||||
use crate::error::HashToCurveError;
|
||||
use ark_ec::short_weierstrass_jacobian::GroupAffine;
|
||||
use ark_ec::{AffineCurve, ProjectiveCurve};
|
||||
use ark_ff::FromBytes;
|
||||
use elliptic_curve::hash2curve::{ExpandMsgXmd, GroupDigest};
|
||||
use elliptic_curve::sec1::ToEncodedPoint;
|
||||
use k256::sha2::Sha256;
|
||||
use k256::AffinePoint;
|
||||
use k256::{ProjectivePoint, Secp256k1};
|
||||
// TODO why not ark libs for these? oO
|
||||
use k256::{sha2::Sha256, AffinePoint, ProjectivePoint, Secp256k1};
|
||||
use secp256k1::Sec1EncodePoint;
|
||||
use tiny_keccak::{Hasher, Shake, Xof};
|
||||
|
||||
pub fn hash_to_curve<Fp: ark_ff::PrimeField, P: ark_ec::SWModelParameters>(
|
||||
msg: &[u8],
|
||||
pk: &GroupAffine<P>,
|
||||
) -> GroupAffine<P> {
|
||||
let pk_encoded = pk.to_encoded_point(true);
|
||||
let b = hex::decode(pk_encoded).unwrap();
|
||||
) -> Result<GroupAffine<P>, HashToCurveError> {
|
||||
let b = hex::decode(&pk.to_encoded_point(true)).expect(super::EXPECT_MSG_DECODE);
|
||||
let x = [msg, b.as_slice()];
|
||||
let x = x.concat().clone();
|
||||
let x = x.as_slice();
|
||||
@@ -24,7 +22,7 @@ pub fn hash_to_curve<Fp: ark_ff::PrimeField, P: ark_ec::SWModelParameters>(
|
||||
&[x],
|
||||
b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_",
|
||||
)
|
||||
.unwrap();
|
||||
.map_err(|_| HashToCurveError::Legacy)?;
|
||||
|
||||
let pt_affine = pt.to_affine();
|
||||
|
||||
@@ -33,13 +31,13 @@ pub fn hash_to_curve<Fp: ark_ff::PrimeField, P: ark_ec::SWModelParameters>(
|
||||
|
||||
pub fn k256_affine_to_arkworks_secp256k1_affine<P: ark_ec::SWModelParameters>(
|
||||
k_pt: AffinePoint,
|
||||
) -> GroupAffine<P> {
|
||||
) -> Result<GroupAffine<P>, HashToCurveError> {
|
||||
let encoded_pt = k_pt.to_encoded_point(false);
|
||||
|
||||
let num_field_bytes = 40;
|
||||
|
||||
// extract k_pt.x
|
||||
let k_pt_x_bytes = encoded_pt.x().unwrap();
|
||||
let k_pt_x_bytes = encoded_pt.x().ok_or(HashToCurveError::Legacy)?;
|
||||
|
||||
// pad x bytes
|
||||
let mut k_pt_x_bytes_vec = vec![0u8; num_field_bytes];
|
||||
@@ -50,10 +48,10 @@ pub fn k256_affine_to_arkworks_secp256k1_affine<P: ark_ec::SWModelParameters>(
|
||||
);
|
||||
}
|
||||
let reader = std::io::BufReader::new(k_pt_x_bytes_vec.as_slice());
|
||||
let g_x = P::BaseField::read(reader).unwrap();
|
||||
let g_x = P::BaseField::read(reader).map_err(|_| HashToCurveError::Legacy)?;
|
||||
|
||||
// extract k_pt.y
|
||||
let k_pt_y_bytes = encoded_pt.y().unwrap();
|
||||
let k_pt_y_bytes = encoded_pt.y().ok_or(HashToCurveError::Legacy)?;
|
||||
|
||||
// pad y bytes
|
||||
let mut k_pt_y_bytes_vec = vec![0u8; num_field_bytes];
|
||||
@@ -65,13 +63,13 @@ pub fn k256_affine_to_arkworks_secp256k1_affine<P: ark_ec::SWModelParameters>(
|
||||
}
|
||||
|
||||
let reader = std::io::BufReader::new(k_pt_y_bytes_vec.as_slice());
|
||||
let g_y = P::BaseField::read(reader).unwrap();
|
||||
let g_y = P::BaseField::read(reader).map_err(|_| HashToCurveError::Legacy)?;
|
||||
|
||||
GroupAffine::<P>::new(g_x, g_y, false)
|
||||
Ok(GroupAffine::<P>::new(g_x, g_y, false))
|
||||
}
|
||||
|
||||
/// Kobi's hash_to_curve function, here for reference only
|
||||
pub fn _try_and_increment<C: ProjectiveCurve>(msg: &[u8]) -> Result<C::Affine, CryptoError> {
|
||||
pub fn _try_and_increment<C: ProjectiveCurve>(msg: &[u8]) -> Result<C::Affine, HashToCurveError> {
|
||||
for nonce in 0u8..=255 {
|
||||
let mut h = Shake::v128();
|
||||
h.update(&[nonce]);
|
||||
@@ -85,5 +83,5 @@ pub fn _try_and_increment<C: ProjectiveCurve>(msg: &[u8]) -> Result<C::Affine, C
|
||||
}
|
||||
}
|
||||
|
||||
Err(CryptoError::CannotHashToCurve)
|
||||
Err(HashToCurveError::ReferenceTryAndIncrement)
|
||||
}
|
||||
|
||||
@@ -1,285 +1,232 @@
|
||||
use crate::error::HashToCurveError;
|
||||
use crate::hash_to_curve::hash_to_curve;
|
||||
use ark_ec::short_weierstrass_jacobian::GroupAffine;
|
||||
use ark_ec::{models::SWModelParameters, AffineCurve, ProjectiveCurve};
|
||||
use ark_ff::PrimeField;
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
|
||||
use ark_std::{rand::Rng, UniformRand};
|
||||
use secp256k1::sec1::Sec1EncodePoint;
|
||||
use sha2::digest::Output;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
mod error;
|
||||
mod hash_to_curve;
|
||||
|
||||
pub mod sig {
|
||||
use crate::error::CryptoError;
|
||||
use crate::hash_to_curve;
|
||||
use ark_ec::short_weierstrass_jacobian::GroupAffine;
|
||||
use ark_ec::{models::SWModelParameters, AffineCurve, ProjectiveCurve};
|
||||
use ark_ff::{PrimeField, ToBytes};
|
||||
use ark_serialize::{
|
||||
CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write,
|
||||
};
|
||||
use ark_std::{marker::PhantomData, rand::Rng, UniformRand};
|
||||
use secp256k1::sec1::Sec1EncodePoint;
|
||||
use sha2::digest::Output;
|
||||
use sha2::{Digest, Sha256};
|
||||
const EXPECT_MSG_DECODE: &str = "the value decoded have been generated by a function which is improbable to output a malformed hexstring (still a place for refactoring)";
|
||||
|
||||
pub enum PlumeVersion {
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
pub struct DeterministicNullifierSignatureScheme<
|
||||
'a,
|
||||
C: ProjectiveCurve,
|
||||
Fq: ark_ff::PrimeField,
|
||||
P: ark_ec::SWModelParameters,
|
||||
> {
|
||||
_group: PhantomData<C>,
|
||||
_field: PhantomData<Fq>,
|
||||
_parameters: PhantomData<P>,
|
||||
_message_lifetime: PhantomData<&'a ()>,
|
||||
pub enum PlumeVersion {
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
pub fn affine_to_bytes<P: SWModelParameters>(point: &GroupAffine<P>) -> Vec<u8> {
|
||||
hex::decode(point.to_encoded_point(true))
|
||||
.expect(EXPECT_MSG_DECODE)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
fn compute_h<'a, C: ProjectiveCurve, Fq: PrimeField, P: SWModelParameters>(
|
||||
pk: &GroupAffine<P>,
|
||||
message: &'a [u8],
|
||||
) -> Result<GroupAffine<P>, HashToCurveError> {
|
||||
//let pk_affine_bytes_vec = affine_to_bytes::<P>(pk);
|
||||
//let m_pk = [message, pk_affine_bytes_vec.as_slice()].concat();
|
||||
//hash_to_curve::try_and_increment::<C>(m_pk.as_slice())
|
||||
hash_to_curve::<Fq, P>(message, pk)
|
||||
}
|
||||
|
||||
fn compute_c_v1<P: SWModelParameters>(
|
||||
g_point: &GroupAffine<P>,
|
||||
pk: &GroupAffine<P>,
|
||||
hashed_to_curve: &GroupAffine<P>,
|
||||
nullifier: &GroupAffine<P>,
|
||||
r_point: &GroupAffine<P>,
|
||||
hashed_to_curve_r: &GroupAffine<P>,
|
||||
) -> Output<Sha256> {
|
||||
// Compute c = sha512([g, pk, h, nul, g^r, z])
|
||||
let c_preimage_vec = [
|
||||
affine_to_bytes::<P>(g_point),
|
||||
affine_to_bytes::<P>(pk),
|
||||
affine_to_bytes::<P>(hashed_to_curve),
|
||||
affine_to_bytes::<P>(nullifier),
|
||||
affine_to_bytes::<P>(r_point),
|
||||
affine_to_bytes::<P>(hashed_to_curve_r),
|
||||
]
|
||||
.concat();
|
||||
|
||||
Sha256::digest(c_preimage_vec.as_slice())
|
||||
}
|
||||
|
||||
fn compute_c_v2<P: SWModelParameters>(
|
||||
nullifier: &GroupAffine<P>,
|
||||
r_point: &GroupAffine<P>,
|
||||
hashed_to_curve_r: &GroupAffine<P>,
|
||||
) -> Output<Sha256> {
|
||||
// Compute c = sha512([nul, g^r, z])
|
||||
let nul_bytes = affine_to_bytes::<P>(nullifier);
|
||||
let g_r_bytes = affine_to_bytes::<P>(r_point);
|
||||
let z_bytes = affine_to_bytes::<P>(hashed_to_curve_r);
|
||||
|
||||
let c_preimage_vec = [nul_bytes, g_r_bytes, z_bytes].concat();
|
||||
|
||||
Sha256::digest(c_preimage_vec.as_slice())
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
ark_serialize_derive::CanonicalSerialize,
|
||||
ark_serialize_derive::CanonicalDeserialize,
|
||||
)]
|
||||
pub struct Parameters<P: SWModelParameters> {
|
||||
pub g_point: GroupAffine<P>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
ark_serialize_derive::CanonicalSerialize,
|
||||
ark_serialize_derive::CanonicalDeserialize,
|
||||
)]
|
||||
pub struct PlumeSignature<P: SWModelParameters> {
|
||||
pub hashed_to_curve_r: GroupAffine<P>,
|
||||
pub r_point: GroupAffine<P>,
|
||||
pub s: P::ScalarField,
|
||||
pub c: P::ScalarField,
|
||||
pub nullifier: GroupAffine<P>,
|
||||
}
|
||||
|
||||
// These aliases should be gone in #88 . If they won't TODO pay attention to the warning about `trait` boundaries being not checked for aliases
|
||||
// also not enforcing trait bounds can impact PublicKey -- it's better to find appropriate upstream type
|
||||
type Message<'a> = &'a [u8];
|
||||
type PublicKey<P: SWModelParameters> = GroupAffine<P>;
|
||||
type SecretKeyMaterial<P: SWModelParameters> = P::ScalarField;
|
||||
|
||||
impl<P: SWModelParameters> PlumeSignature<P> {
|
||||
/// Generate the public key and a private key.
|
||||
fn keygen(pp: &Parameters<P>, rng: &mut impl Rng) -> (PublicKey<P>, SecretKeyMaterial<P>) {
|
||||
let secret_key = SecretKeyMaterial::<P>::rand(rng);
|
||||
let public_key = pp.g_point.mul(secret_key).into();
|
||||
(public_key, secret_key)
|
||||
}
|
||||
|
||||
pub fn affine_to_bytes<P: SWModelParameters>(point: &GroupAffine<P>) -> Vec<u8> {
|
||||
let encoded = point.to_encoded_point(true);
|
||||
let b = hex::decode(encoded).unwrap();
|
||||
b.to_vec()
|
||||
}
|
||||
/// Sign a message using a specified r value
|
||||
fn sign_with_r(
|
||||
pp: &Parameters<P>,
|
||||
keypair: (&PublicKey<P>, &SecretKeyMaterial<P>),
|
||||
message: Message,
|
||||
r_scalar: P::ScalarField,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self, HashToCurveError> {
|
||||
let g_point = pp.g_point;
|
||||
let r_point = g_point.mul(r_scalar).into_affine();
|
||||
|
||||
fn compute_h<'a, C: ProjectiveCurve, Fq: PrimeField, P: SWModelParameters>(
|
||||
pk: &GroupAffine<P>,
|
||||
message: &'a [u8],
|
||||
) -> Result<GroupAffine<P>, CryptoError> {
|
||||
//let pk_affine_bytes_vec = affine_to_bytes::<P>(pk);
|
||||
//let m_pk = [message, pk_affine_bytes_vec.as_slice()].concat();
|
||||
//hash_to_curve::try_and_increment::<C>(m_pk.as_slice())
|
||||
Ok(hash_to_curve::hash_to_curve::<Fq, P>(message, pk))
|
||||
}
|
||||
// Compute h = htc([m, pk])
|
||||
let hashed_to_curve =
|
||||
compute_h::<secp256k1::Projective, secp256k1::fields::Fq, P>(&keypair.0, &message)?;
|
||||
|
||||
// Compute z = h^r
|
||||
let hashed_to_curve_r = hashed_to_curve.mul(r_scalar).into_affine();
|
||||
|
||||
// Compute nul = h^sk
|
||||
let nullifier = hashed_to_curve.mul(*keypair.1).into_affine();
|
||||
|
||||
fn compute_c_v1<P: SWModelParameters>(
|
||||
g_point: &GroupAffine<P>,
|
||||
pk: &GroupAffine<P>,
|
||||
hashed_to_curve: &GroupAffine<P>,
|
||||
nullifier: &GroupAffine<P>,
|
||||
r_point: &GroupAffine<P>,
|
||||
hashed_to_curve_r: &GroupAffine<P>,
|
||||
) -> Output<Sha256> {
|
||||
// Compute c = sha512([g, pk, h, nul, g^r, z])
|
||||
let c_preimage_vec = [
|
||||
affine_to_bytes::<P>(g_point),
|
||||
affine_to_bytes::<P>(pk),
|
||||
affine_to_bytes::<P>(hashed_to_curve),
|
||||
affine_to_bytes::<P>(nullifier),
|
||||
affine_to_bytes::<P>(r_point),
|
||||
affine_to_bytes::<P>(hashed_to_curve_r),
|
||||
]
|
||||
.concat();
|
||||
let c = match version {
|
||||
PlumeVersion::V1 => compute_c_v1::<P>(
|
||||
&g_point,
|
||||
keypair.0,
|
||||
&hashed_to_curve,
|
||||
&nullifier,
|
||||
&r_point,
|
||||
&hashed_to_curve_r,
|
||||
),
|
||||
PlumeVersion::V2 => compute_c_v2(&nullifier, &r_point, &hashed_to_curve_r),
|
||||
};
|
||||
let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref());
|
||||
// Compute s = r + sk ⋅ c
|
||||
let sk_c = keypair.1.into_repr().into() * c_scalar.into_repr().into();
|
||||
let s = r_scalar.into_repr().into() + sk_c;
|
||||
|
||||
Sha256::digest(c_preimage_vec.as_slice())
|
||||
let s_scalar = P::ScalarField::from(s);
|
||||
|
||||
let signature = PlumeSignature {
|
||||
hashed_to_curve_r,
|
||||
s: s_scalar,
|
||||
r_point,
|
||||
c: c_scalar,
|
||||
nullifier,
|
||||
};
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
fn compute_c_v2<P: SWModelParameters>(
|
||||
nullifier: &GroupAffine<P>,
|
||||
r_point: &GroupAffine<P>,
|
||||
hashed_to_curve_r: &GroupAffine<P>,
|
||||
) -> Output<Sha256> {
|
||||
// Compute c = sha512([nul, g^r, z])
|
||||
let nul_bytes = affine_to_bytes::<P>(nullifier);
|
||||
let g_r_bytes = affine_to_bytes::<P>(r_point);
|
||||
let z_bytes = affine_to_bytes::<P>(hashed_to_curve_r);
|
||||
/// Sign a message.
|
||||
fn sign(
|
||||
pp: &Parameters<P>,
|
||||
rng: &mut impl Rng,
|
||||
keypair: (&PublicKey<P>, &SecretKeyMaterial<P>),
|
||||
message: Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self, HashToCurveError> {
|
||||
// Pick a random r from Fp
|
||||
let r_scalar = P::ScalarField::rand(rng);
|
||||
|
||||
let c_preimage_vec = [nul_bytes, g_r_bytes, z_bytes].concat();
|
||||
|
||||
Sha256::digest(c_preimage_vec.as_slice())
|
||||
Self::sign_with_r(pp, keypair, message, r_scalar, version)
|
||||
}
|
||||
|
||||
pub trait VerifiableUnpredictableFunction {
|
||||
type Message: ToBytes;
|
||||
type Parameters: CanonicalSerialize + CanonicalDeserialize;
|
||||
type PublicKey: CanonicalSerialize + CanonicalDeserialize;
|
||||
type SecretKey: CanonicalSerialize + CanonicalDeserialize;
|
||||
type Signature: CanonicalSerialize + CanonicalDeserialize;
|
||||
fn verify_non_zk(
|
||||
self,
|
||||
pp: &Parameters<P>,
|
||||
pk: &PublicKey<P>,
|
||||
message: Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<bool, HashToCurveError> {
|
||||
// Compute h = htc([m, pk])
|
||||
let hashed_to_curve =
|
||||
compute_h::<secp256k1::Projective, secp256k1::fields::Fq, P>(pk, message)?;
|
||||
|
||||
/// Generate a public key and a private key.
|
||||
fn keygen<R: Rng>(
|
||||
pp: &Self::Parameters,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::PublicKey, Self::SecretKey), CryptoError>;
|
||||
|
||||
/// Sign a message.
|
||||
fn sign<R: Rng>(
|
||||
pp: &Self::Parameters,
|
||||
rng: &mut R,
|
||||
keypair: (&Self::PublicKey, &Self::SecretKey),
|
||||
message: Self::Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self::Signature, CryptoError>;
|
||||
|
||||
/// Sign a message using an specified r value
|
||||
fn sign_with_r(
|
||||
pp: &Self::Parameters,
|
||||
keypair: (&Self::PublicKey, &Self::SecretKey),
|
||||
message: Self::Message,
|
||||
r_scalar: Self::SecretKey,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self::Signature, CryptoError>;
|
||||
|
||||
fn verify_non_zk(
|
||||
pp: &Self::Parameters,
|
||||
pk: &Self::PublicKey,
|
||||
sig: &Self::Signature,
|
||||
message: Self::Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<bool, CryptoError>;
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
ark_serialize_derive::CanonicalSerialize,
|
||||
ark_serialize_derive::CanonicalDeserialize,
|
||||
)]
|
||||
pub struct Parameters<P: SWModelParameters> {
|
||||
pub g_point: GroupAffine<P>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
ark_serialize_derive::CanonicalSerialize,
|
||||
ark_serialize_derive::CanonicalDeserialize,
|
||||
)]
|
||||
pub struct Signature<P: SWModelParameters> {
|
||||
pub hashed_to_curve_r: GroupAffine<P>,
|
||||
pub r_point: GroupAffine<P>,
|
||||
pub s: P::ScalarField,
|
||||
pub c: P::ScalarField,
|
||||
pub nullifier: GroupAffine<P>,
|
||||
}
|
||||
|
||||
impl<'a, C: ProjectiveCurve, Fq: PrimeField, P: SWModelParameters>
|
||||
VerifiableUnpredictableFunction for DeterministicNullifierSignatureScheme<'a, C, Fq, P>
|
||||
{
|
||||
type Message = &'a [u8];
|
||||
type Parameters = Parameters<P>;
|
||||
type PublicKey = GroupAffine<P>;
|
||||
type SecretKey = P::ScalarField;
|
||||
type Signature = Signature<P>;
|
||||
|
||||
fn keygen<R: Rng>(
|
||||
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_point.mul(secret_key).into();
|
||||
Ok((public_key, secret_key))
|
||||
}
|
||||
|
||||
fn sign_with_r(
|
||||
pp: &Self::Parameters,
|
||||
keypair: (&Self::PublicKey, &Self::SecretKey),
|
||||
message: Self::Message,
|
||||
r_scalar: P::ScalarField,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self::Signature, CryptoError> {
|
||||
let g_point = pp.g_point;
|
||||
let r_point = g_point.mul(r_scalar).into_affine();
|
||||
|
||||
// Compute h = htc([m, pk])
|
||||
let hashed_to_curve = compute_h::<C, Fq, P>(&keypair.0, &message).unwrap();
|
||||
|
||||
// Compute z = h^r
|
||||
let hashed_to_curve_r = hashed_to_curve.mul(r_scalar).into_affine();
|
||||
|
||||
// Compute nul = h^sk
|
||||
let nullifier = hashed_to_curve.mul(*keypair.1).into_affine();
|
||||
|
||||
// Compute c = sha512([g, pk, h, nul, g^r, z])
|
||||
let c = match version {
|
||||
PlumeVersion::V1 => compute_c_v1::<P>(
|
||||
&g_point,
|
||||
keypair.0,
|
||||
&hashed_to_curve,
|
||||
&nullifier,
|
||||
&r_point,
|
||||
&hashed_to_curve_r,
|
||||
),
|
||||
PlumeVersion::V2 => compute_c_v2(&nullifier, &r_point, &hashed_to_curve_r),
|
||||
};
|
||||
let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref());
|
||||
// Compute s = r + sk ⋅ c
|
||||
let sk_c = keypair.1.into_repr().into() * c_scalar.into_repr().into();
|
||||
let s = r_scalar.into_repr().into() + sk_c;
|
||||
|
||||
let s_scalar = P::ScalarField::from(s);
|
||||
|
||||
let signature = Signature {
|
||||
hashed_to_curve_r,
|
||||
s: s_scalar,
|
||||
r_point,
|
||||
c: c_scalar,
|
||||
nullifier,
|
||||
};
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
fn sign<R: Rng>(
|
||||
pp: &Self::Parameters,
|
||||
rng: &mut R,
|
||||
keypair: (&Self::PublicKey, &Self::SecretKey),
|
||||
message: Self::Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<Self::Signature, CryptoError> {
|
||||
// Pick a random r from Fp
|
||||
let r_scalar: P::ScalarField = Self::SecretKey::rand(rng).into();
|
||||
|
||||
Self::sign_with_r(pp, keypair, message, r_scalar, version)
|
||||
}
|
||||
|
||||
fn verify_non_zk(
|
||||
pp: &Self::Parameters,
|
||||
pk: &Self::PublicKey,
|
||||
sig: &Self::Signature,
|
||||
message: Self::Message,
|
||||
version: PlumeVersion,
|
||||
) -> Result<bool, CryptoError> {
|
||||
// Compute h = htc([m, pk])
|
||||
let hashed_to_curve = compute_h::<C, Fq, P>(pk, message).unwrap();
|
||||
|
||||
// TODO [replace SHA-512](https://github.com/plume-sig/zk-nullifier-sig/issues/39#issuecomment-1732497672)
|
||||
// Compute c' = sha512([g, pk, h, nul, g^r, z]) for v1
|
||||
// c' = sha512([nul, g^r, z]) for v2
|
||||
let c = match version {
|
||||
PlumeVersion::V1 => compute_c_v1::<P>(
|
||||
&pp.g_point,
|
||||
pk,
|
||||
&hashed_to_curve,
|
||||
&sig.nullifier,
|
||||
&sig.r_point,
|
||||
&sig.hashed_to_curve_r,
|
||||
),
|
||||
PlumeVersion::V2 => {
|
||||
compute_c_v2(&sig.nullifier, &sig.r_point, &sig.hashed_to_curve_r)
|
||||
}
|
||||
};
|
||||
let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref());
|
||||
|
||||
// Reject if g^s ⋅ pk^{-c} != g^r
|
||||
let g_s = pp.g_point.mul(sig.s);
|
||||
let pk_c = pk.mul(sig.c);
|
||||
let g_s_pk_c = g_s - pk_c;
|
||||
|
||||
if sig.r_point != g_s_pk_c {
|
||||
return Ok(false);
|
||||
// TODO [replace SHA-512](https://github.com/plume-sig/zk-nullifier-sig/issues/39#issuecomment-1732497672)
|
||||
// Compute c' = sha512([g, pk, h, nul, g^r, z]) for v1
|
||||
// c' = sha512([nul, g^r, z]) for v2
|
||||
let c = match version {
|
||||
PlumeVersion::V1 => compute_c_v1::<P>(
|
||||
&pp.g_point,
|
||||
pk,
|
||||
&hashed_to_curve,
|
||||
&self.nullifier,
|
||||
&self.r_point,
|
||||
&self.hashed_to_curve_r,
|
||||
),
|
||||
PlumeVersion::V2 => {
|
||||
compute_c_v2(&self.nullifier, &self.r_point, &self.hashed_to_curve_r)
|
||||
}
|
||||
};
|
||||
let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref());
|
||||
|
||||
// Reject if h^s ⋅ nul^{-c} = z
|
||||
let h_s = hashed_to_curve.mul(sig.s);
|
||||
let nul_c = sig.nullifier.mul(sig.c);
|
||||
let h_s_nul_c = h_s - nul_c;
|
||||
// Reject if g^s ⋅ pk^{-c} != g^r
|
||||
let g_s = pp.g_point.mul(self.s);
|
||||
let pk_c = pk.mul(self.c);
|
||||
let g_s_pk_c = g_s - pk_c;
|
||||
|
||||
if sig.hashed_to_curve_r != h_s_nul_c {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Reject if c != c'
|
||||
if c_scalar != sig.c {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
if self.r_point != g_s_pk_c {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Reject if h^s ⋅ nul^{-c} = z
|
||||
let h_s = hashed_to_curve.mul(self.s);
|
||||
let nul_c = self.nullifier.mul(self.c);
|
||||
let h_s_nul_c = h_s - nul_c;
|
||||
|
||||
if self.hashed_to_curve_r != h_s_nul_c {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Reject if c != c'
|
||||
if c_scalar != self.c {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use crate::hash_to_curve::{hash_to_curve, k256_affine_to_arkworks_secp256k1_affine};
|
||||
use crate::sig::DeterministicNullifierSignatureScheme;
|
||||
use crate::sig::PlumeVersion;
|
||||
use crate::sig::VerifiableUnpredictableFunction;
|
||||
use crate::{PlumeSignature, PlumeVersion};
|
||||
use ark_ec::models::short_weierstrass_jacobian::GroupAffine;
|
||||
use ark_ec::{AffineCurve, ProjectiveCurve};
|
||||
use ark_ff::biginteger;
|
||||
@@ -13,7 +11,7 @@ use secp256k1::curves::Affine;
|
||||
use secp256k1::curves::Secp256k1Parameters;
|
||||
use secp256k1::fields::Fq;
|
||||
|
||||
type Parameters = crate::sig::Parameters<Secp256k1Parameters>;
|
||||
type Parameters = crate::Parameters<Secp256k1Parameters>;
|
||||
|
||||
fn test_template() -> (ThreadRng, Affine) {
|
||||
let rng = thread_rng();
|
||||
@@ -22,9 +20,6 @@ fn test_template() -> (ThreadRng, Affine) {
|
||||
(rng, g)
|
||||
}
|
||||
|
||||
type Scheme<'a> =
|
||||
DeterministicNullifierSignatureScheme<'a, secp256k1::Projective, Fq, Secp256k1Parameters>;
|
||||
|
||||
#[test]
|
||||
pub fn test_k256_affine_to_arkworks_secp256k1_affine() {
|
||||
for i in 1..50 {
|
||||
@@ -41,7 +36,7 @@ pub fn test_k256_affine_to_arkworks_secp256k1_affine() {
|
||||
k256_affine_to_arkworks_secp256k1_affine::<Secp256k1Parameters>(k256_pt.to_affine());
|
||||
|
||||
// The points should match
|
||||
assert_eq!(ark_pt.into_affine(), converted_pt);
|
||||
assert_eq!(ark_pt.into_affine(), converted_pt.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +79,7 @@ pub fn test_keygen() {
|
||||
let (mut rng, g) = test_template();
|
||||
let pp = Parameters { g_point: g };
|
||||
|
||||
let (pk, sk) = Scheme::keygen(&pp, &mut rng).unwrap();
|
||||
let (pk, sk) = PlumeSignature::keygen(&pp, &mut rng);
|
||||
|
||||
let expected_pk = g.mul(sk);
|
||||
assert_eq!(pk, expected_pk);
|
||||
@@ -96,9 +91,9 @@ pub fn test_sign_and_verify() {
|
||||
let pp = Parameters { g_point: g };
|
||||
|
||||
let message = b"Message";
|
||||
let keypair = Scheme::keygen(&pp, &mut rng).unwrap();
|
||||
let keypair = PlumeSignature::keygen(&pp, &mut rng);
|
||||
|
||||
let sig = Scheme::sign(
|
||||
let sig = PlumeSignature::sign(
|
||||
&pp,
|
||||
&mut rng,
|
||||
(&keypair.0, &keypair.1),
|
||||
@@ -107,10 +102,10 @@ pub fn test_sign_and_verify() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let is_valid = Scheme::verify_non_zk(&pp, &keypair.0, &sig, message, PlumeVersion::V1);
|
||||
let is_valid = sig.verify_non_zk(&pp, &keypair.0, message, PlumeVersion::V1);
|
||||
assert!(is_valid.unwrap());
|
||||
|
||||
let sig = Scheme::sign(
|
||||
let sig = PlumeSignature::sign(
|
||||
&pp,
|
||||
&mut rng,
|
||||
(&keypair.0, &keypair.1),
|
||||
@@ -119,7 +114,7 @@ pub fn test_sign_and_verify() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let is_valid = Scheme::verify_non_zk(&pp, &keypair.0, &sig, message, PlumeVersion::V2);
|
||||
let is_valid = sig.verify_non_zk(&pp, &keypair.0, message, PlumeVersion::V2);
|
||||
assert!(is_valid.unwrap());
|
||||
}
|
||||
|
||||
@@ -132,8 +127,7 @@ pub fn compute_h() -> GroupAffine<Secp256k1Parameters> {
|
||||
let pk_projective = g.mul(sk);
|
||||
let pk = GroupAffine::<Secp256k1Parameters>::from(pk_projective);
|
||||
|
||||
let h = hash_to_curve::<secp256k1::fields::Fq, Secp256k1Parameters>(message, &pk);
|
||||
h
|
||||
hash_to_curve::<secp256k1::fields::Fq, Secp256k1Parameters>(message, &pk).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -236,7 +230,8 @@ pub fn test_against_zk_nullifier_sig_c_and_s() {
|
||||
|
||||
let keypair = (pk, sk);
|
||||
let sig =
|
||||
Scheme::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V1).unwrap();
|
||||
PlumeSignature::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V1)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
coord_to_hex(sig.c.into()),
|
||||
@@ -248,7 +243,8 @@ pub fn test_against_zk_nullifier_sig_c_and_s() {
|
||||
);
|
||||
|
||||
let sig =
|
||||
Scheme::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V2).unwrap();
|
||||
PlumeSignature::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V2)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
coord_to_hex(sig.c.into()),
|
||||
|
||||
Reference in New Issue
Block a user