Skip to content

Commit a66398f

Browse files
authored
Bump ark-vrf version (paritytech#11395)
- Bump ark-vrf from 0.1.0 to 0.2.2 - Extract vrf_sign_io and vrf_verify_io helper functions in the bandersnatch VRF module and reuse the helpers in both the VrfSecret/VrfPublic trait impls and the TraitPair sign/verify methods, eliminating duplicated proving/verifying logic
1 parent 8416b6e commit a66398f

4 files changed

Lines changed: 144 additions & 73 deletions

File tree

Cargo.lock

Lines changed: 76 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -644,24 +644,24 @@ approx = { version = "0.5.1" }
644644
aquamarine = { version = "0.5.0" }
645645
arbitrary = { version = "1.3.2" }
646646
ark-bls12-377 = { version = "0.5.0", default-features = false }
647-
ark-bls12-377-ext = { version = "0.5.0", default-features = false }
647+
ark-bls12-377-ext = { version = "0.5.2", default-features = false }
648648
ark-bls12-381 = { version = "0.5.0", default-features = false }
649-
ark-bls12-381-ext = { version = "0.5.0", default-features = false }
649+
ark-bls12-381-ext = { version = "0.5.2", default-features = false }
650650
ark-bw6-761 = { version = "0.5.0", default-features = false }
651-
ark-bw6-761-ext = { version = "0.5.0", default-features = false }
651+
ark-bw6-761-ext = { version = "0.5.2", default-features = false }
652652
ark-ec = { version = "0.5.0", default-features = false }
653653
ark-ed-on-bls12-377 = { version = "0.5.0", default-features = false }
654-
ark-ed-on-bls12-377-ext = { version = "0.5.0", default-features = false }
654+
ark-ed-on-bls12-377-ext = { version = "0.5.2", default-features = false }
655655
ark-ed-on-bls12-381-bandersnatch = { version = "0.5.0", default-features = false }
656-
ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.5.0", default-features = false }
656+
ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.5.2", default-features = false }
657657
ark-ff = { version = "0.5.0", default-features = false }
658658
ark-pallas = { version = "0.5.0", default-features = false }
659-
ark-pallas-ext = { version = "0.5.0", default-features = false }
659+
ark-pallas-ext = { version = "0.5.2", default-features = false }
660660
ark-scale = { version = "0.0.13", default-features = false }
661661
ark-std = { version = "0.5.0", default-features = false }
662662
ark-vesta = { version = "0.5.0", default-features = false }
663-
ark-vesta-ext = { version = "0.5.0", default-features = false }
664-
ark-vrf = { version = "0.1.0", default-features = false }
663+
ark-vesta-ext = { version = "0.5.2", default-features = false }
664+
ark-vrf = { version = "0.2.2", default-features = false }
665665
array-bytes = { version = "6.2.2", default-features = false }
666666
arrayvec = { version = "0.7.4" }
667667
assert_cmd = { version = "2.0.14" }

prdoc/pr_11395.prdoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
title: 'bandersnatch: extract vrf_sign_io/vrf_verify_io helpers'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Extract vrf_sign_io and vrf_verify_io helper functions in the bandersnatch
6+
VRF module and reuse them in both the VRF trait impls and the TraitPair
7+
sign/verify methods (with zero input). This removes duplicated
8+
proving/verifying logic and fixes the TraitPair::sign implementation which
9+
was previously using a manual Schnorr scheme inconsistent with verification.
10+
crates:
11+
- name: sp-core
12+
bump: minor
13+
- name: sp-crypto-ec-utils
14+
bump: minor

substrate/primitives/core/src/bandersnatch.rs

Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ use crate::{
3131
};
3232
use alloc::{vec, vec::Vec};
3333
use ark_vrf::{
34-
reexports::{
35-
ark_ec::CurveGroup,
36-
ark_serialize::{CanonicalDeserialize, CanonicalSerialize},
37-
},
34+
reexports::ark_serialize::{CanonicalDeserialize, CanonicalSerialize},
3835
suites::bandersnatch::{self, BandersnatchSha512Ell2 as BandersnatchSuite, Secret},
3936
Suite,
4037
};
@@ -153,34 +150,17 @@ impl TraitPair for Pair {
153150

154151
#[cfg(feature = "full_crypto")]
155152
fn sign(&self, data: &[u8]) -> Signature {
156-
// Deterministic nonce for plain Schnorr signature.
157-
// Inspired by ed25519 <https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6>
158-
let h_in = [&self.prefix[..32], data].concat();
159-
let h = &ark_vrf::utils::hash::<<BandersnatchSuite as Suite>::Hasher>(&h_in)[..32];
160-
let k = ark_vrf::codec::scalar_decode::<BandersnatchSuite>(h);
161-
let gk = BandersnatchSuite::generator() * k;
162-
let c = BandersnatchSuite::challenge(&[&gk.into_affine(), &self.secret.public.0], data);
163-
let s = k + c * self.secret.scalar;
164-
let mut raw_signature = [0_u8; SIGNATURE_SERIALIZED_SIZE];
165-
bandersnatch::IetfProof { c, s }
166-
.serialize_compressed(&mut raw_signature.as_mut_slice())
167-
.expect("serialization length is constant and checked by test; qed");
168-
Signature::from_raw(raw_signature)
153+
let zero = bandersnatch::AffinePoint::zero();
154+
vrf::vrf_sign_io(&self.secret, bandersnatch::Input::from_affine(zero), data).proof
169155
}
170156

171157
fn verify<M: AsRef<[u8]>>(signature: &Signature, data: M, public: &Public) -> bool {
172-
let Ok(signature) = bandersnatch::IetfProof::deserialize_compressed(&signature.0[..])
173-
else {
174-
return false;
158+
let zero = bandersnatch::AffinePoint::zero();
159+
let vrf_sig = vrf::VrfSignature {
160+
pre_output: vrf::VrfPreOutput(bandersnatch::Output::from_affine(zero)),
161+
proof: *signature,
175162
};
176-
let Ok(public) = bandersnatch::Public::deserialize_compressed(&public.0[..]) else {
177-
return false;
178-
};
179-
let gs = BandersnatchSuite::generator() * signature.s;
180-
let yc = public.0 * signature.c;
181-
let rv = gs - yc;
182-
let cv = BandersnatchSuite::challenge(&[&rv.into_affine(), &public.0], data.as_ref());
183-
signature.c == cv
163+
vrf::vrf_verify_io(public, bandersnatch::Input::from_affine(zero), &vrf_sig, data.as_ref())
184164
}
185165

186166
/// Return a vector filled with the seed.
@@ -236,7 +216,7 @@ pub mod vrf {
236216
impl Decode for VrfPreOutput {
237217
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
238218
let buf = <[u8; PREOUT_SERIALIZED_SIZE]>::decode(i)?;
239-
let preout = bandersnatch::Output::deserialize_compressed_unchecked(buf.as_slice())
219+
let preout = bandersnatch::Output::deserialize_compressed(buf.as_slice())
240220
.map_err(|_| "vrf-preout decode error: bad preout")?;
241221
Ok(VrfPreOutput(preout))
242222
}
@@ -314,18 +294,44 @@ pub mod vrf {
314294
type VrfSignature = VrfSignature;
315295
}
316296

297+
#[cfg(feature = "full_crypto")]
298+
pub(super) fn vrf_sign_io(
299+
secret: &Secret,
300+
input: bandersnatch::Input,
301+
aux_data: &[u8],
302+
) -> VrfSignature {
303+
use ark_vrf::ietf::Prover;
304+
let output = secret.output(input);
305+
let pre_output = VrfPreOutput(output);
306+
let proof_impl = secret.prove(input, output, aux_data);
307+
let mut proof = Signature::default();
308+
proof_impl
309+
.serialize_compressed(proof.0.as_mut_slice())
310+
.expect("serialization length is constant and checked by test; qed");
311+
VrfSignature { pre_output, proof }
312+
}
313+
314+
pub(super) fn vrf_verify_io(
315+
public: &Public,
316+
input: bandersnatch::Input,
317+
signature: &VrfSignature,
318+
aux_data: &[u8],
319+
) -> bool {
320+
use ark_vrf::ietf::Verifier;
321+
let Ok(public) = bandersnatch::Public::deserialize_compressed(public.as_slice()) else {
322+
return false;
323+
};
324+
let Ok(proof) = ark_vrf::ietf::Proof::deserialize_compressed(signature.proof.as_slice())
325+
else {
326+
return false;
327+
};
328+
public.verify(input, signature.pre_output.0, aux_data, &proof).is_ok()
329+
}
330+
317331
#[cfg(feature = "full_crypto")]
318332
impl VrfSecret for Pair {
319333
fn vrf_sign(&self, data: &VrfSignData) -> VrfSignature {
320-
use ark_vrf::ietf::Prover;
321-
let pre_output_impl = self.secret.output(data.vrf_input.0);
322-
let pre_output = VrfPreOutput(pre_output_impl);
323-
let proof_impl = self.secret.prove(data.vrf_input.0, pre_output.0, &data.aux_data);
324-
let mut proof = Signature::default();
325-
proof_impl
326-
.serialize_compressed(proof.0.as_mut_slice())
327-
.expect("serialization length is constant and checked by test; qed");
328-
VrfSignature { pre_output, proof }
334+
vrf_sign_io(&self.secret, data.vrf_input.0, &data.aux_data)
329335
}
330336

331337
fn vrf_pre_output(&self, input: &Self::VrfInput) -> Self::VrfPreOutput {
@@ -343,20 +349,7 @@ pub mod vrf {
343349

344350
impl VrfPublic for Public {
345351
fn vrf_verify(&self, data: &VrfSignData, signature: &VrfSignature) -> bool {
346-
use ark_vrf::ietf::Verifier;
347-
let Ok(public) =
348-
bandersnatch::Public::deserialize_compressed_unchecked(self.as_slice())
349-
else {
350-
return false;
351-
};
352-
let Ok(proof) =
353-
ark_vrf::ietf::Proof::deserialize_compressed_unchecked(signature.proof.as_slice())
354-
else {
355-
return false;
356-
};
357-
public
358-
.verify(data.vrf_input.0, signature.pre_output.0, &data.aux_data, &proof)
359-
.is_ok()
352+
vrf_verify_io(self, data.vrf_input.0, signature, &data.aux_data)
360353
}
361354
}
362355

@@ -581,8 +574,7 @@ pub mod ring_vrf {
581574
/// from which the [`RingVerifier`] has been constructed.
582575
pub fn ring_vrf_verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool {
583576
use ark_vrf::ring::Verifier;
584-
let Ok(proof) =
585-
bandersnatch::RingProof::deserialize_compressed_unchecked(self.proof.as_slice())
577+
let Ok(proof) = bandersnatch::RingProof::deserialize_compressed(self.proof.as_slice())
586578
else {
587579
return false;
588580
};

0 commit comments

Comments
 (0)