mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-23 21:15:41 +00:00
Bandersnatch: ring-context generic over domain size (#2581)
Serialized length is now statically computed depending on the domain size. Opens the primitive to more generic usages not related to Sassafras expectations Address one point of https://github.com/paritytech/polkadot-sdk/issues/2364
This commit is contained in:
@@ -23,10 +23,16 @@ use sp_consensus_slots::Slot;
|
|||||||
use sp_std::vec::Vec;
|
use sp_std::vec::Vec;
|
||||||
|
|
||||||
pub use sp_core::bandersnatch::{
|
pub use sp_core::bandersnatch::{
|
||||||
ring_vrf::{RingContext, RingProver, RingVerifier, RingVerifierData, RingVrfSignature},
|
ring_vrf::{RingProver, RingVerifier, RingVerifierData, RingVrfSignature},
|
||||||
vrf::{VrfInput, VrfOutput, VrfSignData, VrfSignature},
|
vrf::{VrfInput, VrfOutput, VrfSignData, VrfSignature},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Ring VRF domain size for Sassafras consensus.
|
||||||
|
pub const RING_VRF_DOMAIN_SIZE: u32 = 2048;
|
||||||
|
|
||||||
|
/// Bandersnatch VRF [`RingContext`] specialization for Sassafras using [`RING_VRF_DOMAIN_SIZE`].
|
||||||
|
pub type RingContext = sp_core::bandersnatch::ring_vrf::RingContext<RING_VRF_DOMAIN_SIZE>;
|
||||||
|
|
||||||
fn vrf_input_from_data(
|
fn vrf_input_from_data(
|
||||||
domain: &[u8],
|
domain: &[u8],
|
||||||
data: impl IntoIterator<Item = impl AsRef<[u8]>>,
|
data: impl IntoIterator<Item = impl AsRef<[u8]>>,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
|
|||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
|
|
||||||
use sp_runtime_interface::pass_by::PassByInner;
|
use sp_runtime_interface::pass_by::PassByInner;
|
||||||
use sp_std::{boxed::Box, vec::Vec};
|
use sp_std::{vec, vec::Vec};
|
||||||
|
|
||||||
/// Identifier used to match public keys against bandersnatch-vrf keys.
|
/// Identifier used to match public keys against bandersnatch-vrf keys.
|
||||||
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band");
|
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band");
|
||||||
@@ -622,31 +622,25 @@ pub mod ring_vrf {
|
|||||||
pub use bandersnatch_vrfs::ring::{RingProof, RingProver, RingVerifier, KZG};
|
pub use bandersnatch_vrfs::ring::{RingProof, RingProver, RingVerifier, KZG};
|
||||||
use bandersnatch_vrfs::{ring::VerifierKey, CanonicalDeserialize, PublicKey};
|
use bandersnatch_vrfs::{ring::VerifierKey, CanonicalDeserialize, PublicKey};
|
||||||
|
|
||||||
/// Ring max size (keyset max size).
|
/// Overhead in the domain size with respect to the supported ring size.
|
||||||
pub const RING_MAX_SIZE: u32 = RING_DOMAIN_MAX_SIZE - RING_DOMAIN_OVERHEAD;
|
|
||||||
|
|
||||||
/// Ring domain max size.
|
|
||||||
pub const RING_DOMAIN_MAX_SIZE: u32 = 2048;
|
|
||||||
|
|
||||||
/// Overhead in the domain size over the max ring size.
|
|
||||||
///
|
///
|
||||||
/// Some bits of the domain are reserved for the zk proof to work.
|
/// Some bits of the domain are reserved for the zk-proof to work.
|
||||||
pub(crate) const RING_DOMAIN_OVERHEAD: u32 = 257;
|
pub const RING_DOMAIN_OVERHEAD: u32 = 257;
|
||||||
|
|
||||||
// Max size of serialized ring-vrf context params.
|
// Max size of serialized ring-vrf context given `domain_len`.
|
||||||
//
|
pub(crate) const fn ring_context_serialized_size(domain_len: u32) -> usize {
|
||||||
// The actual size is dependent on the ring domain size and this value
|
// const G1_POINT_COMPRESSED_SIZE: usize = 48;
|
||||||
// has been computed for `RING_DOMAIN_MAX_SIZE` with compression disabled
|
// const G2_POINT_COMPRESSED_SIZE: usize = 96;
|
||||||
// for performance reasons.
|
const G1_POINT_UNCOMPRESSED_SIZE: usize = 96;
|
||||||
//
|
const G2_POINT_UNCOMPRESSED_SIZE: usize = 192;
|
||||||
// 1024 uncompressed
|
const OVERHEAD_SIZE: usize = 20;
|
||||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 295412;
|
const G2_POINTS_NUM: usize = 2;
|
||||||
// 1024 compressed
|
let g1_points_num = 3 * domain_len as usize + 1;
|
||||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 147716;
|
|
||||||
// 2048 uncompressed
|
OVERHEAD_SIZE +
|
||||||
pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 590324;
|
g1_points_num * G1_POINT_UNCOMPRESSED_SIZE +
|
||||||
// 2048 compressed
|
G2_POINTS_NUM * G2_POINT_UNCOMPRESSED_SIZE
|
||||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 295172;
|
}
|
||||||
|
|
||||||
pub(crate) const RING_VERIFIER_DATA_SERIALIZED_SIZE: usize = 388;
|
pub(crate) const RING_VERIFIER_DATA_SERIALIZED_SIZE: usize = 388;
|
||||||
pub(crate) const RING_SIGNATURE_SERIALIZED_SIZE: usize = 755;
|
pub(crate) const RING_SIGNATURE_SERIALIZED_SIZE: usize = 755;
|
||||||
@@ -705,15 +699,17 @@ pub mod ring_vrf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Context used to construct ring prover and verifier.
|
/// Context used to construct ring prover and verifier.
|
||||||
|
///
|
||||||
|
/// Generic parameter `D` represents the ring domain size and drives
|
||||||
|
/// the max number of supported ring members [`RingContext::max_keyset_size`]
|
||||||
|
/// which is equal to `D - RING_DOMAIN_OVERHEAD`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RingContext(KZG);
|
pub struct RingContext<const D: u32>(KZG);
|
||||||
|
|
||||||
impl RingContext {
|
impl<const D: u32> RingContext<D> {
|
||||||
/// Build an dummy instance for testing purposes.
|
/// Build an dummy instance for testing purposes.
|
||||||
///
|
|
||||||
/// `domain_size` is set to `RING_DOMAIN_MAX_SIZE`.
|
|
||||||
pub fn new_testing() -> Self {
|
pub fn new_testing() -> Self {
|
||||||
Self(KZG::testing_kzg_setup([0; 32], RING_DOMAIN_MAX_SIZE))
|
Self(KZG::testing_kzg_setup([0; 32], D))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the keyset max size.
|
/// Get the keyset max size.
|
||||||
@@ -761,38 +757,45 @@ pub mod ring_vrf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for RingContext {
|
impl<const D: u32> Encode for RingContext<D> {
|
||||||
fn encode(&self) -> Vec<u8> {
|
fn encode(&self) -> Vec<u8> {
|
||||||
let mut buf = Box::new([0; RING_CONTEXT_SERIALIZED_MAX_SIZE]);
|
let mut buf = vec![0; ring_context_serialized_size(D)];
|
||||||
self.0
|
self.0
|
||||||
.serialize_uncompressed(buf.as_mut_slice())
|
.serialize_uncompressed(buf.as_mut_slice())
|
||||||
.expect("serialization length is constant and checked by test; qed");
|
.expect("serialization length is constant and checked by test; qed");
|
||||||
buf.encode()
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for RingContext {
|
impl<const D: u32> Decode for RingContext<D> {
|
||||||
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
|
fn decode<R: codec::Input>(input: &mut R) -> Result<Self, codec::Error> {
|
||||||
let buf = <Box<[u8; RING_CONTEXT_SERIALIZED_MAX_SIZE]>>::decode(i)?;
|
let mut buf = vec![0; ring_context_serialized_size(D)];
|
||||||
|
input.read(&mut buf[..])?;
|
||||||
let kzg = KZG::deserialize_uncompressed_unchecked(buf.as_slice())
|
let kzg = KZG::deserialize_uncompressed_unchecked(buf.as_slice())
|
||||||
.map_err(|_| "KZG decode error")?;
|
.map_err(|_| "KZG decode error")?;
|
||||||
Ok(RingContext(kzg))
|
Ok(RingContext(kzg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EncodeLike for RingContext {}
|
impl<const D: u32> EncodeLike for RingContext<D> {}
|
||||||
|
|
||||||
impl MaxEncodedLen for RingContext {
|
impl<const D: u32> MaxEncodedLen for RingContext<D> {
|
||||||
fn max_encoded_len() -> usize {
|
fn max_encoded_len() -> usize {
|
||||||
<[u8; RING_CONTEXT_SERIALIZED_MAX_SIZE]>::max_encoded_len()
|
ring_context_serialized_size(D)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInfo for RingContext {
|
impl<const D: u32> TypeInfo for RingContext<D> {
|
||||||
type Identity = [u8; RING_CONTEXT_SERIALIZED_MAX_SIZE];
|
type Identity = Self;
|
||||||
|
|
||||||
fn type_info() -> scale_info::Type {
|
fn type_info() -> scale_info::Type {
|
||||||
Self::Identity::type_info()
|
let path = scale_info::Path::new("RingContext", module_path!());
|
||||||
|
let array_type_def = scale_info::TypeDefArray {
|
||||||
|
len: ring_context_serialized_size(D) as u32,
|
||||||
|
type_param: scale_info::MetaType::new::<u8>(),
|
||||||
|
};
|
||||||
|
let type_def = scale_info::TypeDef::Array(array_type_def);
|
||||||
|
scale_info::Type { path, type_params: Vec::new(), type_def, docs: Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,7 +906,11 @@ pub mod ring_vrf {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{ring_vrf::*, vrf::*, *};
|
use super::{ring_vrf::*, vrf::*, *};
|
||||||
use crate::crypto::{VrfPublic, VrfSecret, DEV_PHRASE};
|
use crate::crypto::{VrfPublic, VrfSecret, DEV_PHRASE};
|
||||||
|
|
||||||
const DEV_SEED: &[u8; SEED_SERIALIZED_SIZE] = &[0xcb; SEED_SERIALIZED_SIZE];
|
const DEV_SEED: &[u8; SEED_SERIALIZED_SIZE] = &[0xcb; SEED_SERIALIZED_SIZE];
|
||||||
|
const TEST_DOMAIN_SIZE: u32 = 1024;
|
||||||
|
|
||||||
|
type TestRingContext = RingContext<TEST_DOMAIN_SIZE>;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn b2h(bytes: &[u8]) -> String {
|
fn b2h(bytes: &[u8]) -> String {
|
||||||
@@ -916,10 +923,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn backend_assumptions_sanity_check() {
|
fn backend_assumptions_sanity_check() {
|
||||||
let kzg = KZG::testing_kzg_setup([0; 32], RING_DOMAIN_MAX_SIZE);
|
let kzg = KZG::testing_kzg_setup([0; 32], TEST_DOMAIN_SIZE);
|
||||||
assert_eq!(kzg.max_keyset_size() as u32, RING_MAX_SIZE);
|
assert_eq!(kzg.max_keyset_size() as u32, TEST_DOMAIN_SIZE - RING_DOMAIN_OVERHEAD);
|
||||||
|
|
||||||
assert_eq!(kzg.uncompressed_size(), RING_CONTEXT_SERIALIZED_MAX_SIZE);
|
assert_eq!(kzg.uncompressed_size(), ring_context_serialized_size(TEST_DOMAIN_SIZE));
|
||||||
|
|
||||||
let pks: Vec<_> = (0..16)
|
let pks: Vec<_> = (0..16)
|
||||||
.map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into())
|
.map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into())
|
||||||
@@ -1071,7 +1078,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ring_vrf_sign_verify() {
|
fn ring_vrf_sign_verify() {
|
||||||
let ring_ctx = RingContext::new_testing();
|
let ring_ctx = TestRingContext::new_testing();
|
||||||
|
|
||||||
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
||||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||||
@@ -1097,7 +1104,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ring_vrf_sign_verify_with_out_of_ring_key() {
|
fn ring_vrf_sign_verify_with_out_of_ring_key() {
|
||||||
let ring_ctx = RingContext::new_testing();
|
let ring_ctx = TestRingContext::new_testing();
|
||||||
|
|
||||||
let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
||||||
let pair = Pair::from_seed(DEV_SEED);
|
let pair = Pair::from_seed(DEV_SEED);
|
||||||
@@ -1116,7 +1123,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ring_vrf_make_bytes_matches() {
|
fn ring_vrf_make_bytes_matches() {
|
||||||
let ring_ctx = RingContext::new_testing();
|
let ring_ctx = TestRingContext::new_testing();
|
||||||
|
|
||||||
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
||||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||||
@@ -1145,7 +1152,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode_ring_vrf_signature() {
|
fn encode_decode_ring_vrf_signature() {
|
||||||
let ring_ctx = RingContext::new_testing();
|
let ring_ctx = TestRingContext::new_testing();
|
||||||
|
|
||||||
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
||||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||||
@@ -1177,13 +1184,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode_ring_vrf_context() {
|
fn encode_decode_ring_vrf_context() {
|
||||||
let ctx1 = RingContext::new_testing();
|
let ctx1 = TestRingContext::new_testing();
|
||||||
let enc1 = ctx1.encode();
|
let enc1 = ctx1.encode();
|
||||||
|
|
||||||
assert_eq!(enc1.len(), RING_CONTEXT_SERIALIZED_MAX_SIZE);
|
let _ti = <TestRingContext as TypeInfo>::type_info();
|
||||||
assert_eq!(RingContext::max_encoded_len(), RING_CONTEXT_SERIALIZED_MAX_SIZE);
|
|
||||||
|
|
||||||
let ctx2 = RingContext::decode(&mut enc1.as_slice()).unwrap();
|
assert_eq!(enc1.len(), ring_context_serialized_size(TEST_DOMAIN_SIZE));
|
||||||
|
assert_eq!(enc1.len(), TestRingContext::max_encoded_len());
|
||||||
|
|
||||||
|
let ctx2 = TestRingContext::decode(&mut enc1.as_slice()).unwrap();
|
||||||
let enc2 = ctx2.encode();
|
let enc2 = ctx2.encode();
|
||||||
|
|
||||||
assert_eq!(enc1, enc2);
|
assert_eq!(enc1, enc2);
|
||||||
@@ -1191,7 +1200,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode_verifier_data() {
|
fn encode_decode_verifier_data() {
|
||||||
let ring_ctx = RingContext::new_testing();
|
let ring_ctx = TestRingContext::new_testing();
|
||||||
|
|
||||||
let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect();
|
||||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ mod tests {
|
|||||||
|
|
||||||
let store = MemoryKeystore::new();
|
let store = MemoryKeystore::new();
|
||||||
|
|
||||||
let ring_ctx = bandersnatch::ring_vrf::RingContext::new_testing();
|
let ring_ctx = bandersnatch::ring_vrf::RingContext::<1024>::new_testing();
|
||||||
|
|
||||||
let mut pks: Vec<_> = (0..16)
|
let mut pks: Vec<_> = (0..16)
|
||||||
.map(|i| bandersnatch::Pair::from_seed(&[i as u8; 32]).public())
|
.map(|i| bandersnatch::Pair::from_seed(&[i as u8; 32]).public())
|
||||||
|
|||||||
Reference in New Issue
Block a user