Bandersnatch tweaks after backend update (#1482)

This commit is contained in:
Davide Galassi
2023-09-13 13:32:39 +02:00
committed by GitHub
parent 0bebc8ae96
commit 61be78c621
3 changed files with 114 additions and 111 deletions
Generated
+8 -8
View File
@@ -513,7 +513,7 @@ dependencies = [
[[package]]
name = "ark-secret-scalar"
version = "0.0.2"
source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4"
dependencies = [
"ark-ec",
"ark-ff",
@@ -561,7 +561,7 @@ dependencies = [
[[package]]
name = "ark-transcript"
version = "0.0.2"
source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4"
dependencies = [
"ark-ff",
"ark-serialize",
@@ -1240,13 +1240,12 @@ dependencies = [
[[package]]
name = "bandersnatch_vrfs"
version = "0.0.1"
source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4"
dependencies = [
"ark-bls12-381",
"ark-ec",
"ark-ed-on-bls12-381-bandersnatch",
"ark-ff",
"ark-scale",
"ark-serialize",
"ark-std",
"dleq_vrf",
@@ -2704,7 +2703,7 @@ dependencies = [
[[package]]
name = "common"
version = "0.1.0"
source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213"
source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895"
dependencies = [
"ark-ec",
"ark-ff",
@@ -2713,6 +2712,7 @@ dependencies = [
"ark-std",
"fflonk",
"merlin 3.0.0",
"rand_chacha 0.3.1",
]
[[package]]
@@ -4424,7 +4424,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
[[package]]
name = "dleq_vrf"
version = "0.0.2"
source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4"
dependencies = [
"ark-ec",
"ark-ff",
@@ -13961,13 +13961,14 @@ dependencies = [
[[package]]
name = "ring"
version = "0.1.0"
source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213"
source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895"
dependencies = [
"ark-ec",
"ark-ff",
"ark-poly",
"ark-serialize",
"ark-std",
"blake2",
"common",
"fflonk",
"merlin 3.0.0",
@@ -16971,7 +16972,6 @@ name = "sp-core"
version = "21.0.0"
dependencies = [
"array-bytes",
"arrayvec 0.7.4",
"bandersnatch_vrfs",
"bitflags 1.3.2",
"blake2",
+1 -3
View File
@@ -13,7 +13,6 @@ documentation = "https://docs.rs/sp-core"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
arrayvec = { version = "0.7.2", default-features = false }
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive","max-encoded-len"] }
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
log = { version = "0.4.17", default-features = false }
@@ -58,7 +57,7 @@ sp-runtime-interface = { path = "../runtime-interface", default-features = false
# bls crypto
w3f-bls = { version = "0.1.3", default-features = false, optional = true}
# bandersnatch crypto
bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "3119f51", default-features = false, optional = true }
bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "f4fe253", default-features = false, optional = true }
[dev-dependencies]
criterion = "0.4.0"
@@ -76,7 +75,6 @@ bench = false
default = [ "std" ]
std = [
"array-bytes",
"arrayvec/std",
"bandersnatch_vrfs/getrandom",
"blake2/std",
"bounded-collections/std",
+105 -100
View File
@@ -53,9 +53,8 @@ const SEED_SERIALIZED_LEN: usize = 32;
// Short-Weierstrass form serialized sizes.
const PUBLIC_SERIALIZED_LEN: usize = 33;
const SIGNATURE_SERIALIZED_LEN: usize = 65;
const RING_SIGNATURE_SERIALIZED_LEN: usize = 755;
const PREOUT_SERIALIZED_LEN: usize = 33;
const PEDERSEN_SIGNATURE_SERIALIZED_LEN: usize = 163;
const RING_PROOF_SERIALIZED_LEN: usize = 592;
// Max size of serialized ring-vrf context params.
//
@@ -69,7 +68,7 @@ const RING_PROOF_SERIALIZED_LEN: usize = 592;
// 2048 → 295 KB
// NOTE: This is quite big but looks like there is an upcoming fix
// in the backend.
const RING_CONTEXT_SERIALIZED_LEN: usize = 147752;
const RING_CONTEXT_SERIALIZED_LEN: usize = 147748;
/// Bandersnatch public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
@@ -278,7 +277,7 @@ impl TraitPair for Pair {
let mut raw = [0; PUBLIC_SERIALIZED_LEN];
public
.serialize_compressed(raw.as_mut_slice())
.expect("key buffer length is good; qed");
.expect("serialization length is constant and checked by test; qed");
Public::unchecked_from(raw)
}
@@ -356,7 +355,7 @@ pub mod vrf {
let mut bytes = [0; PREOUT_SERIALIZED_LEN];
self.0
.serialize_compressed(bytes.as_mut_slice())
.expect("preout serialization can't fail");
.expect("serialization length is constant and checked by test; qed");
bytes.encode()
}
}
@@ -506,7 +505,7 @@ pub mod vrf {
}
fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput {
let output = self.secret.0.vrf_preout(&input.0);
let output = self.secret.vrf_preout(&input.0);
VrfOutput(output)
}
}
@@ -539,24 +538,26 @@ pub mod vrf {
#[cfg(feature = "full_crypto")]
impl Pair {
fn vrf_sign_gen<const N: usize>(&self, data: &VrfSignData) -> VrfSignature {
let ios: Vec<_> = data
.inputs
.iter()
.map(|i| self.secret.clone().0.vrf_inout(i.0.clone()))
.collect();
let ios = core::array::from_fn(|i| {
let input = data.inputs[i].0.clone();
self.secret.vrf_inout(input)
});
let signature: ThinVrfSignature<N> =
self.secret.sign_thin_vrf(data.transcript.clone(), ios.as_slice());
let thin_signature: ThinVrfSignature<N> =
self.secret.sign_thin_vrf(data.transcript.clone(), &ios);
let mut sign_bytes = [0; SIGNATURE_SERIALIZED_LEN];
signature
.signature
.serialize_compressed(sign_bytes.as_mut_slice())
.expect("serialization can't fail");
let outputs: Vec<_> = signature.preoutputs.into_iter().map(VrfOutput).collect();
let outputs: Vec<_> = thin_signature.preouts.into_iter().map(VrfOutput).collect();
let outputs = VrfIosVec::truncate_from(outputs);
VrfSignature { signature: Signature(sign_bytes), outputs }
let mut signature =
VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_LEN]), outputs };
thin_signature
.proof
.serialize_compressed(signature.signature.0.as_mut_slice())
.expect("serialization length is constant and checked by test; qed");
signature
}
/// Generate an arbitrary number of bytes from the given `context` and VRF `input`.
@@ -566,7 +567,7 @@ pub mod vrf {
input: &VrfInput,
) -> [u8; N] {
let transcript = Transcript::new_labeled(context);
let inout = self.secret.clone().0.vrf_inout(input.0.clone());
let inout = self.secret.vrf_inout(input.0.clone());
inout.vrf_output_bytes(transcript)
}
}
@@ -581,30 +582,23 @@ pub mod vrf {
return false
};
let Ok(preouts) = signature
.outputs
.iter()
.map(|o| o.0.clone())
.collect::<arrayvec::ArrayVec<bandersnatch_vrfs::VrfPreOut, N>>()
.into_inner()
else {
return false
};
let preouts: [bandersnatch_vrfs::VrfPreOut; N] =
core::array::from_fn(|i| signature.outputs[i].0.clone());
// Deserialize only the proof, the rest has already been deserialized
// This is another hack used because backend signature type is generic over
// the number of ios.
let Ok(signature) =
let Ok(proof) =
ThinVrfSignature::<0>::deserialize_compressed(signature.signature.as_ref())
.map(|s| s.signature)
.map(|s| s.proof)
else {
return false
};
let signature = ThinVrfSignature { signature, preoutputs: preouts };
let signature = ThinVrfSignature { proof, preouts };
let inputs = data.inputs.iter().map(|i| i.0.clone());
signature.verify_thin_vrf(data.transcript.clone(), inputs, &public).is_ok()
public.verify_thin_vrf(data.transcript.clone(), inputs, &signature).is_ok()
}
}
@@ -627,7 +621,7 @@ pub mod vrf {
pub mod ring_vrf {
use super::{vrf::*, *};
pub use bandersnatch_vrfs::ring::{RingProof, RingProver, RingVerifier, KZG};
use bandersnatch_vrfs::{CanonicalDeserialize, PedersenVrfSignature, PublicKey};
use bandersnatch_vrfs::{CanonicalDeserialize, PublicKey};
/// Context used to produce ring signatures.
#[derive(Clone)]
@@ -649,7 +643,7 @@ pub mod ring_vrf {
let mut pks = Vec::with_capacity(public_keys.len());
for public_key in public_keys {
let pk = PublicKey::deserialize_compressed(public_key.as_slice()).ok()?;
pks.push(pk.0 .0.into());
pks.push(pk.0.into());
}
let prover_key = self.0.prover_key(pks);
@@ -662,7 +656,7 @@ pub mod ring_vrf {
let mut pks = Vec::with_capacity(public_keys.len());
for public_key in public_keys {
let pk = PublicKey::deserialize_compressed(public_key.as_slice()).ok()?;
pks.push(pk.0 .0.into());
pks.push(pk.0.into());
}
let verifier_key = self.0.verifier_key(pks);
@@ -676,7 +670,7 @@ pub mod ring_vrf {
let mut buf = Box::new([0; RING_CONTEXT_SERIALIZED_LEN]);
self.0
.serialize_compressed(buf.as_mut_slice())
.expect("preout serialization can't fail");
.expect("serialization length is constant and checked by test; qed");
buf.encode()
}
}
@@ -711,10 +705,8 @@ pub mod ring_vrf {
pub struct RingVrfSignature {
/// VRF (pre)outputs.
pub outputs: VrfIosVec<VrfOutput>,
/// Pedersen VRF signature.
pub signature: [u8; PEDERSEN_SIGNATURE_SERIALIZED_LEN],
/// Ring proof.
pub ring_proof: [u8; RING_PROOF_SERIALIZED_LEN],
/// Ring signature.
pub signature: [u8; RING_SIGNATURE_SERIALIZED_LEN],
}
#[cfg(feature = "full_crypto")]
@@ -741,31 +733,27 @@ pub mod ring_vrf {
data: &VrfSignData,
prover: &RingProver,
) -> RingVrfSignature {
let ios: Vec<_> = data
.inputs
.iter()
.map(|i| self.secret.clone().0.vrf_inout(i.0.clone()))
.collect();
let ios = core::array::from_fn(|i| {
let input = data.inputs[i].0.clone();
self.secret.vrf_inout(input)
});
let ring_signature: bandersnatch_vrfs::RingVrfSignature<N> =
self.secret.sign_ring_vrf(data.transcript.clone(), ios.as_slice(), prover);
bandersnatch_vrfs::RingProver { ring_prover: prover, secret: &self.secret }
.sign_ring_vrf(data.transcript.clone(), &ios);
let outputs: Vec<_> = ring_signature.preoutputs.into_iter().map(VrfOutput).collect();
let outputs: Vec<_> = ring_signature.preouts.into_iter().map(VrfOutput).collect();
let outputs = VrfIosVec::truncate_from(outputs);
let mut signature = [0; PEDERSEN_SIGNATURE_SERIALIZED_LEN];
ring_signature
.signature
.serialize_compressed(signature.as_mut_slice())
.expect("ped-signature serialization can't fail");
let mut signature =
RingVrfSignature { outputs, signature: [0; RING_SIGNATURE_SERIALIZED_LEN] };
let mut ring_proof = [0; RING_PROOF_SERIALIZED_LEN];
ring_signature
.ring_proof
.serialize_compressed(ring_proof.as_mut_slice())
.expect("ring-proof serialization can't fail");
.proof
.serialize_compressed(signature.signature.as_mut_slice())
.expect("serialization length is constant and checked by test; qed");
RingVrfSignature { outputs, signature, ring_proof }
signature
}
}
@@ -774,7 +762,7 @@ pub mod ring_vrf {
///
/// The signature is verifiable if it has been produced by a member of the ring
/// from which the [`RingVerifier`] has been constructed.
pub fn verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool {
pub fn ring_vrf_verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool {
const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3");
let preouts_len = self.outputs.len();
if preouts_len != data.inputs.len() {
@@ -782,43 +770,37 @@ pub mod ring_vrf {
}
// Workaround to overcome backend signature generic over the number of IOs.
match preouts_len {
0 => self.verify_gen::<0>(data, verifier),
1 => self.verify_gen::<1>(data, verifier),
2 => self.verify_gen::<2>(data, verifier),
3 => self.verify_gen::<3>(data, verifier),
0 => self.ring_vrf_verify_gen::<0>(data, verifier),
1 => self.ring_vrf_verify_gen::<1>(data, verifier),
2 => self.ring_vrf_verify_gen::<2>(data, verifier),
3 => self.ring_vrf_verify_gen::<3>(data, verifier),
_ => unreachable!(),
}
}
fn verify_gen<const N: usize>(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool {
let Ok(preoutputs) = self
.outputs
.iter()
.map(|o| o.0.clone())
.collect::<arrayvec::ArrayVec<bandersnatch_vrfs::VrfPreOut, N>>()
.into_inner()
fn ring_vrf_verify_gen<const N: usize>(
&self,
data: &VrfSignData,
verifier: &RingVerifier,
) -> bool {
let Ok(vrf_signature) =
bandersnatch_vrfs::RingVrfSignature::<0>::deserialize_compressed(
self.signature.as_slice(),
)
else {
return false
};
let Ok(signature) =
PedersenVrfSignature::deserialize_compressed(self.signature.as_slice())
else {
return false
};
let preouts: [bandersnatch_vrfs::VrfPreOut; N] =
core::array::from_fn(|i| self.outputs[i].0.clone());
let Ok(ring_proof) = RingProof::deserialize_compressed(self.ring_proof.as_slice())
else {
return false
};
let ring_signature =
bandersnatch_vrfs::RingVrfSignature { signature, preoutputs, ring_proof };
let signature =
bandersnatch_vrfs::RingVrfSignature { proof: vrf_signature.proof, preouts };
let inputs = data.inputs.iter().map(|i| i.0.clone());
ring_signature
.verify_ring_vrf(data.transcript.clone(), inputs, verifier)
bandersnatch_vrfs::RingVerifier(verifier)
.verify_ring_vrf(data.transcript.clone(), inputs, &signature)
.is_ok()
}
}
@@ -840,16 +822,41 @@ mod tests {
}
#[test]
fn assumptions_sanity_check() {
// Backend
let ring_ctx = RingContext::new_testing();
let pair = SecretKey::from_seed(DEV_SEED);
let public = pair.to_public();
fn backend_assumptions_sanity_check() {
let kzg = KZG::testing_kzg_setup([0; 32], RING_DOMAIN_SIZE as u32);
assert_eq!(kzg.max_keyset_size(), RING_DOMAIN_SIZE - 257);
assert_eq!(kzg.compressed_size(), RING_CONTEXT_SERIALIZED_LEN);
assert_eq!(public.0.size_of_serialized(), PUBLIC_SERIALIZED_LEN);
assert_eq!(ring_ctx.max_keyset_size(), RING_DOMAIN_SIZE - 257);
let pks: Vec<_> = (0..16)
.map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into())
.collect();
// Wrapper
let secret = SecretKey::from_seed(&[0u8; 32]);
let public = secret.to_public();
assert_eq!(public.compressed_size(), PUBLIC_SERIALIZED_LEN);
let input = VrfInput::new(b"foo", &[]);
let preout = secret.vrf_preout(&input.0);
assert_eq!(preout.compressed_size(), PREOUT_SERIALIZED_LEN);
let prover_key = kzg.prover_key(pks);
let ring_prover = kzg.init_ring_prover(prover_key, 0);
let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], None);
let thin_signature: bandersnatch_vrfs::ThinVrfSignature<0> =
secret.sign_thin_vrf(data.transcript.clone(), &[]);
assert_eq!(thin_signature.compressed_size(), SIGNATURE_SERIALIZED_LEN);
let ring_signature: bandersnatch_vrfs::RingVrfSignature<0> =
bandersnatch_vrfs::RingProver { ring_prover: &ring_prover, secret: &secret }
.sign_ring_vrf(data.transcript.clone(), &[]);
assert_eq!(ring_signature.compressed_size(), RING_SIGNATURE_SERIALIZED_LEN);
}
#[test]
fn max_vrf_ios_bound_respected() {
let inputs: Vec<_> = (0..MAX_VRF_IOS - 1).map(|_| VrfInput::new(b"", &[])).collect();
let mut sign_data = VrfSignData::new(b"", &[b""], inputs).unwrap();
let res = sign_data.push_vrf_input(VrfInput::new(b"", b""));
@@ -987,7 +994,7 @@ mod tests {
let signature = pair.ring_vrf_sign(&data, &prover);
let verifier = ring_ctx.verifier(&pks).unwrap();
assert!(signature.verify(&data, &verifier));
assert!(signature.ring_vrf_verify(&data, &verifier));
}
#[test]
@@ -1006,7 +1013,7 @@ mod tests {
let signature = pair.ring_vrf_sign(&data, &prover);
let verifier = ring_ctx.verifier(&pks).unwrap();
assert!(!signature.verify(&data, &verifier));
assert!(!signature.ring_vrf_verify(&data, &verifier));
}
#[test]
@@ -1062,10 +1069,8 @@ mod tests {
let bytes = expected.encode();
let expected_len = data.inputs.len() * PREOUT_SERIALIZED_LEN +
PEDERSEN_SIGNATURE_SERIALIZED_LEN +
RING_PROOF_SERIALIZED_LEN +
1;
let expected_len =
data.inputs.len() * PREOUT_SERIALIZED_LEN + RING_SIGNATURE_SERIALIZED_LEN + 1;
assert_eq!(bytes.len(), expected_len);
let decoded = RingVrfSignature::decode(&mut bytes.as_slice()).unwrap();