mirror of
https://github.com/arnaucube/arkeddsa.git
synced 2026-01-12 00:01:28 +01:00
better bounds
reuse ark-error
This commit is contained in:
94
src/eddsa.rs
94
src/eddsa.rs
@@ -3,7 +3,10 @@ use ark_crypto_primitives::sponge::{
|
|||||||
poseidon::{PoseidonConfig, PoseidonSponge},
|
poseidon::{PoseidonConfig, PoseidonSponge},
|
||||||
Absorb, CryptographicSponge,
|
Absorb, CryptographicSponge,
|
||||||
};
|
};
|
||||||
use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr, CurveGroup};
|
use ark_ec::{
|
||||||
|
twisted_edwards::{Affine, TECurveConfig},
|
||||||
|
AffineRepr,
|
||||||
|
};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use digest::OutputSizeUser;
|
use digest::OutputSizeUser;
|
||||||
@@ -41,41 +44,48 @@ impl SecretKey {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
/// `PublicKey` is EdDSA signature verification key
|
/// `PublicKey` is EdDSA signature verification key
|
||||||
pub struct PublicKey<A: AffineRepr>(A)
|
pub struct PublicKey<TE: TECurveConfig>(Affine<TE>);
|
||||||
where
|
|
||||||
A::Config: TECurveConfig;
|
|
||||||
|
|
||||||
impl<A: AffineRepr> PublicKey<A>
|
impl<TE: TECurveConfig> PublicKey<TE> {
|
||||||
where
|
pub fn point(&self) -> &Affine<TE> {
|
||||||
A::Config: TECurveConfig,
|
&self.0
|
||||||
{
|
}
|
||||||
pub fn xy(&self) -> (&A::BaseField, &A::BaseField) {
|
|
||||||
self.0.xy().unwrap()
|
pub fn xy(&self) -> (&TE::BaseField, &TE::BaseField) {
|
||||||
|
self.as_ref().xy().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TE: TECurveConfig> From<Affine<TE>> for PublicKey<TE> {
|
||||||
|
fn from(affine: Affine<TE>) -> Self {
|
||||||
|
Self(affine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TE: TECurveConfig> AsRef<Affine<TE>> for PublicKey<TE> {
|
||||||
|
fn as_ref(&self) -> &Affine<TE> {
|
||||||
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
/// `SigningKey` produces EdDSA signatures for given message
|
/// `SigningKey` produces EdDSA signatures for given message
|
||||||
pub struct SigningKey<A: AffineRepr>
|
pub struct SigningKey<TE: TECurveConfig> {
|
||||||
where
|
|
||||||
A::Config: TECurveConfig,
|
|
||||||
{
|
|
||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
public_key: PublicKey<A>,
|
public_key: PublicKey<TE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AffineRepr> SigningKey<A>
|
impl<TE: TECurveConfig> SigningKey<TE>
|
||||||
where
|
where
|
||||||
A::Config: TECurveConfig,
|
TE::BaseField: PrimeField + Absorb,
|
||||||
A::BaseField: PrimeField + Absorb,
|
|
||||||
{
|
{
|
||||||
pub fn new<D: Digest>(secret_key: &SecretKey) -> Result<Self, Error> {
|
pub fn new<D: Digest>(secret_key: &SecretKey) -> Result<Self, Error> {
|
||||||
(<D as OutputSizeUser>::output_size() == 64)
|
(<D as OutputSizeUser>::output_size() == 64)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or(Error::BadOutputSize)?;
|
.ok_or(Error::BadDigestOutput)?;
|
||||||
|
|
||||||
let (x, _) = secret_key.expand::<A::ScalarField, D>();
|
let (x, _) = secret_key.expand::<TE::ScalarField, D>();
|
||||||
let public_key: A = (A::generator() * x).into_affine();
|
let public_key: Affine<TE> = (Affine::<TE>::generator() * x).into();
|
||||||
let signing_key = Self {
|
let signing_key = Self {
|
||||||
secret_key: *secret_key,
|
secret_key: *secret_key,
|
||||||
public_key: PublicKey(public_key),
|
public_key: PublicKey(public_key),
|
||||||
@@ -90,35 +100,36 @@ where
|
|||||||
Self::new::<D>(&secret_key)
|
Self::new::<D>(&secret_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn public_key(&self) -> &PublicKey<A> {
|
pub fn public_key(&self) -> &PublicKey<TE> {
|
||||||
&self.public_key
|
&self.public_key
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign<D: Digest, E: Absorb>(
|
pub fn sign<D: Digest, E: Absorb>(
|
||||||
&self,
|
&self,
|
||||||
poseidon: &PoseidonConfig<A::BaseField>,
|
poseidon: &PoseidonConfig<TE::BaseField>,
|
||||||
message: &[E],
|
message: &[E],
|
||||||
) -> Signature<A> {
|
) -> Signature<TE> {
|
||||||
let (x, prefix) = self.secret_key.expand::<A::ScalarField, D>();
|
let (x, prefix) = self.secret_key.expand::<TE::ScalarField, D>();
|
||||||
|
|
||||||
let mut h = D::new();
|
let mut h = D::new();
|
||||||
h.update(prefix);
|
h.update(prefix);
|
||||||
message
|
message
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|m| h.update(m.to_sponge_bytes_as_vec()));
|
.for_each(|m| h.update(m.to_sponge_bytes_as_vec()));
|
||||||
let r: A::ScalarField = crate::from_digest(h);
|
let r: TE::ScalarField = crate::from_digest(h);
|
||||||
let sig_r = (A::generator() * r).into_affine();
|
let sig_r: Affine<TE> = (Affine::<TE>::generator() * r).into();
|
||||||
|
|
||||||
let mut poseidon = PoseidonSponge::new(poseidon);
|
let mut poseidon = PoseidonSponge::new(poseidon);
|
||||||
|
|
||||||
let (sig_r_x, sig_r_y) = sig_r.xy().unwrap();
|
let (sig_r_x, sig_r_y) = sig_r.xy().unwrap();
|
||||||
poseidon.absorb(sig_r_x);
|
poseidon.absorb(sig_r_x);
|
||||||
poseidon.absorb(sig_r_y);
|
poseidon.absorb(sig_r_y);
|
||||||
let (vk_x, vk_y) = self.public_key.0.xy().unwrap();
|
let (pk_x, pk_y) = self.public_key.0.xy().unwrap();
|
||||||
poseidon.absorb(vk_x);
|
poseidon.absorb(pk_x);
|
||||||
poseidon.absorb(vk_y);
|
poseidon.absorb(pk_y);
|
||||||
message.iter().for_each(|m| poseidon.absorb(m));
|
message.iter().for_each(|m| poseidon.absorb(m));
|
||||||
|
|
||||||
let k = poseidon.squeeze_field_elements::<A::ScalarField>(1);
|
let k = poseidon.squeeze_field_elements::<TE::ScalarField>(1);
|
||||||
let k = k.first().unwrap();
|
let k = k.first().unwrap();
|
||||||
|
|
||||||
let sig_s = (x * k) + r;
|
let sig_s = (x * k) + r;
|
||||||
@@ -127,33 +138,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AffineRepr> PublicKey<A>
|
impl<TE: TECurveConfig> PublicKey<TE>
|
||||||
where
|
where
|
||||||
A::Config: TECurveConfig,
|
TE::BaseField: PrimeField + Absorb,
|
||||||
A::BaseField: PrimeField + Absorb,
|
|
||||||
{
|
{
|
||||||
pub fn verify<E: Absorb>(
|
pub fn verify<E: Absorb>(
|
||||||
&self,
|
&self,
|
||||||
poseidon: &PoseidonConfig<A::BaseField>,
|
poseidon: &PoseidonConfig<TE::BaseField>,
|
||||||
message: &[E],
|
message: &[E],
|
||||||
signature: &Signature<A>,
|
signature: &Signature<TE>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut poseidon = PoseidonSponge::new(poseidon);
|
let mut poseidon = PoseidonSponge::new(poseidon);
|
||||||
|
|
||||||
let (sig_r_x, sig_r_y) = signature.r().xy().unwrap();
|
let (sig_r_x, sig_r_y) = signature.r().xy().unwrap();
|
||||||
poseidon.absorb(sig_r_x);
|
poseidon.absorb(sig_r_x);
|
||||||
poseidon.absorb(sig_r_y);
|
poseidon.absorb(sig_r_y);
|
||||||
let (vk_x, vk_y) = self.0.xy().unwrap();
|
let (pk_x, pk_y) = self.0.xy().unwrap();
|
||||||
poseidon.absorb(vk_x);
|
poseidon.absorb(pk_x);
|
||||||
poseidon.absorb(vk_y);
|
poseidon.absorb(pk_y);
|
||||||
message.iter().for_each(|m| poseidon.absorb(m));
|
message.iter().for_each(|m| poseidon.absorb(m));
|
||||||
|
|
||||||
let k = poseidon.squeeze_field_elements::<A::ScalarField>(1);
|
let k = poseidon.squeeze_field_elements::<TE::ScalarField>(1);
|
||||||
let k = k.first().unwrap();
|
let k = k.first().unwrap();
|
||||||
|
|
||||||
let kx_b = self.0 * k;
|
let kx_b = self.0 * k;
|
||||||
let s_b = A::generator() * signature.s();
|
let s_b = Affine::<TE>::generator() * signature.s();
|
||||||
let r_rec: A = (s_b - kx_b).into();
|
let r_rec: Affine<TE> = (s_b - kx_b).into();
|
||||||
|
|
||||||
(signature.r() == &r_rec).then_some(()).ok_or(Error::Verify)
|
(signature.r() == &r_rec).then_some(()).ok_or(Error::Verify)
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/lib.rs
33
src/lib.rs
@@ -14,17 +14,27 @@ pub(crate) fn from_digest<F: PrimeField, D: Digest>(digest: D) -> F {
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Verify,
|
Verify,
|
||||||
BadOutputSize,
|
BadDigestOutput,
|
||||||
InvalidData,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Error::Verify => write!(f, "Signature verification failed"),
|
||||||
|
Error::BadDigestOutput => write!(f, "Bad digest output size"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ark_std::error::Error for Error {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use crate::SigningKey;
|
use crate::SigningKey;
|
||||||
use ark_crypto_primitives::sponge::poseidon::{find_poseidon_ark_and_mds, PoseidonConfig};
|
use ark_crypto_primitives::sponge::poseidon::{find_poseidon_ark_and_mds, PoseidonConfig};
|
||||||
use ark_crypto_primitives::sponge::Absorb;
|
use ark_crypto_primitives::sponge::Absorb;
|
||||||
use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr};
|
use ark_ec::twisted_edwards::TECurveConfig;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
@@ -46,13 +56,12 @@ mod test {
|
|||||||
PoseidonConfig::new(full_rounds, partial_rounds, 5, mds, ark, rate, 1)
|
PoseidonConfig::new(full_rounds, partial_rounds, 5, mds, ark, rate, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_test<A: AffineRepr, D: Digest>()
|
fn run_test<TE: TECurveConfig, D: Digest>()
|
||||||
where
|
where
|
||||||
A::BaseField: Absorb + PrimeField,
|
TE::BaseField: Absorb + PrimeField,
|
||||||
A::Config: TECurveConfig,
|
|
||||||
{
|
{
|
||||||
let poseidon = poseidon_config(4, 8, 55);
|
let poseidon = poseidon_config(4, 8, 55);
|
||||||
let signing_key = SigningKey::<A>::generate::<D>(&mut OsRng).unwrap();
|
let signing_key = SigningKey::<TE>::generate::<D>(&mut OsRng).unwrap();
|
||||||
let message = b"xxx yyy <<< zzz >>> bunny";
|
let message = b"xxx yyy <<< zzz >>> bunny";
|
||||||
let signature = signing_key.sign::<D, _>(&poseidon, &message[..]);
|
let signature = signing_key.sign::<D, _>(&poseidon, &message[..]);
|
||||||
let public_key = signing_key.public_key();
|
let public_key = signing_key.public_key();
|
||||||
@@ -63,10 +72,10 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eddsa() {
|
fn test_eddsa() {
|
||||||
run_test::<ark_ed_on_bn254::EdwardsAffine, sha2::Sha512>();
|
run_test::<ark_ed_on_bn254::EdwardsConfig, sha2::Sha512>();
|
||||||
run_test::<ark_ed_on_bn254::EdwardsAffine, blake2::Blake2b512>();
|
run_test::<ark_ed_on_bn254::EdwardsConfig, blake2::Blake2b512>();
|
||||||
run_test::<crate::ed_on_bn254_twist::EdwardsAffine, sha2::Sha512>();
|
run_test::<crate::ed_on_bn254_twist::EdwardsConfig, sha2::Sha512>();
|
||||||
run_test::<ark_ed_on_bls12_381::EdwardsAffine, sha2::Sha512>();
|
run_test::<ark_ed_on_bls12_381::EdwardsConfig, sha2::Sha512>();
|
||||||
run_test::<ark_ed_on_bls12_381_bandersnatch::EdwardsAffine, sha2::Sha512>();
|
run_test::<ark_ed_on_bls12_381_bandersnatch::EdwardsConfig, sha2::Sha512>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
use crate::Error;
|
use ark_ec::twisted_edwards::Affine;
|
||||||
use ark_ec::twisted_edwards::TECurveConfig;
|
use ark_ec::twisted_edwards::TECurveConfig;
|
||||||
use ark_ec::AffineRepr;
|
|
||||||
use ark_serialize::CanonicalDeserialize;
|
use ark_serialize::CanonicalDeserialize;
|
||||||
use ark_serialize::CanonicalSerialize;
|
use ark_serialize::CanonicalSerialize;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
/// `SignatureComponents` contains the realized parts of a signature
|
/// `SignatureComponents` contains the realized parts of a signature
|
||||||
pub struct Signature<A: AffineRepr> {
|
pub struct Signature<TE: TECurveConfig> {
|
||||||
r: A,
|
r: Affine<TE>,
|
||||||
s: A::ScalarField,
|
s: TE::ScalarField,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AffineRepr> Signature<A>
|
impl<TE: TECurveConfig> Signature<TE> {
|
||||||
where
|
|
||||||
A::Config: TECurveConfig,
|
|
||||||
{
|
|
||||||
/// Serializes the signature components to bytes as uncompressed.
|
/// Serializes the signature components to bytes as uncompressed.
|
||||||
/// Expect output size to be `size_of(A::BaseField) * 2 + size_of(A::ScalarField)`
|
/// Expect output size to be `size_of(TE::BaseField) * 2 + size_of(TE::ScalarField)`
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
self.r.serialize_uncompressed(&mut bytes).unwrap();
|
self.r.serialize_uncompressed(&mut bytes).unwrap();
|
||||||
@@ -25,32 +21,30 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checked deserialization of the signature components from bytes.
|
/// Checked deserialization of the signature components from bytes.
|
||||||
/// Expects input size to be `size_of(A::BaseField) * 2 + size_of(A::ScalarField)`
|
/// Expects input size to be `size_of(TE::BaseField) * 2 + size_of(TE::ScalarField)`
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Signature<A>, Error> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Box<dyn ark_std::error::Error>> {
|
||||||
let point_size = A::Config::serialized_size(ark_serialize::Compress::No);
|
let point_size = TE::serialized_size(ark_serialize::Compress::No);
|
||||||
(bytes.len() == 32 + A::Config::serialized_size(ark_serialize::Compress::No))
|
(bytes.len() == 32 + TE::serialized_size(ark_serialize::Compress::No))
|
||||||
.then_some(true)
|
.then_some(true)
|
||||||
.ok_or(Error::InvalidData)?;
|
.ok_or(ark_serialize::SerializationError::InvalidData)?;
|
||||||
|
|
||||||
let off1 = point_size;
|
let off1 = point_size;
|
||||||
let off2 = off1 + 32;
|
let off2 = off1 + 32;
|
||||||
|
|
||||||
let r =
|
let r = Affine::<TE>::deserialize_uncompressed(&bytes[00..off1])?;
|
||||||
A::deserialize_uncompressed(&bytes[00..off1]).map_err(|_| crate::Error::InvalidData)?;
|
let s = TE::ScalarField::deserialize_uncompressed(&bytes[off1..off2])?;
|
||||||
let s = A::ScalarField::deserialize_uncompressed(&bytes[off1..off2])
|
|
||||||
.map_err(|_| crate::Error::InvalidData)?;
|
|
||||||
Ok(Signature { r, s })
|
Ok(Signature { r, s })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(r: A, s: A::ScalarField) -> Self {
|
pub fn new(r: Affine<TE>, s: TE::ScalarField) -> Self {
|
||||||
Self { r, s }
|
Self { r, s }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn r(&self) -> &A {
|
pub fn r(&self) -> &Affine<TE> {
|
||||||
&self.r
|
&self.r
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn s(&self) -> &A::ScalarField {
|
pub fn s(&self) -> &TE::ScalarField {
|
||||||
&self.s
|
&self.s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user