mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 19:07:57 +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:
@@ -39,7 +39,7 @@ use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
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.
|
||||
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};
|
||||
use bandersnatch_vrfs::{ring::VerifierKey, CanonicalDeserialize, PublicKey};
|
||||
|
||||
/// Ring max size (keyset max 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.
|
||||
/// Overhead in the domain size with respect to the supported ring size.
|
||||
///
|
||||
/// Some bits of the domain are reserved for the zk proof to work.
|
||||
pub(crate) const RING_DOMAIN_OVERHEAD: u32 = 257;
|
||||
/// Some bits of the domain are reserved for the zk-proof to work.
|
||||
pub const RING_DOMAIN_OVERHEAD: u32 = 257;
|
||||
|
||||
// Max size of serialized ring-vrf context params.
|
||||
//
|
||||
// The actual size is dependent on the ring domain size and this value
|
||||
// has been computed for `RING_DOMAIN_MAX_SIZE` with compression disabled
|
||||
// for performance reasons.
|
||||
//
|
||||
// 1024 uncompressed
|
||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 295412;
|
||||
// 1024 compressed
|
||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 147716;
|
||||
// 2048 uncompressed
|
||||
pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 590324;
|
||||
// 2048 compressed
|
||||
// pub(crate) const RING_CONTEXT_SERIALIZED_MAX_SIZE: usize = 295172;
|
||||
// Max size of serialized ring-vrf context given `domain_len`.
|
||||
pub(crate) const fn ring_context_serialized_size(domain_len: u32) -> usize {
|
||||
// const G1_POINT_COMPRESSED_SIZE: usize = 48;
|
||||
// const G2_POINT_COMPRESSED_SIZE: usize = 96;
|
||||
const G1_POINT_UNCOMPRESSED_SIZE: usize = 96;
|
||||
const G2_POINT_UNCOMPRESSED_SIZE: usize = 192;
|
||||
const OVERHEAD_SIZE: usize = 20;
|
||||
const G2_POINTS_NUM: usize = 2;
|
||||
let g1_points_num = 3 * domain_len as usize + 1;
|
||||
|
||||
OVERHEAD_SIZE +
|
||||
g1_points_num * G1_POINT_UNCOMPRESSED_SIZE +
|
||||
G2_POINTS_NUM * G2_POINT_UNCOMPRESSED_SIZE
|
||||
}
|
||||
|
||||
pub(crate) const RING_VERIFIER_DATA_SERIALIZED_SIZE: usize = 388;
|
||||
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.
|
||||
///
|
||||
/// 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)]
|
||||
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.
|
||||
///
|
||||
/// `domain_size` is set to `RING_DOMAIN_MAX_SIZE`.
|
||||
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.
|
||||
@@ -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> {
|
||||
let mut buf = Box::new([0; RING_CONTEXT_SERIALIZED_MAX_SIZE]);
|
||||
let mut buf = vec![0; ring_context_serialized_size(D)];
|
||||
self.0
|
||||
.serialize_uncompressed(buf.as_mut_slice())
|
||||
.expect("serialization length is constant and checked by test; qed");
|
||||
buf.encode()
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for RingContext {
|
||||
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
|
||||
let buf = <Box<[u8; RING_CONTEXT_SERIALIZED_MAX_SIZE]>>::decode(i)?;
|
||||
impl<const D: u32> Decode for RingContext<D> {
|
||||
fn decode<R: codec::Input>(input: &mut R) -> Result<Self, codec::Error> {
|
||||
let mut buf = vec![0; ring_context_serialized_size(D)];
|
||||
input.read(&mut buf[..])?;
|
||||
let kzg = KZG::deserialize_uncompressed_unchecked(buf.as_slice())
|
||||
.map_err(|_| "KZG decode error")?;
|
||||
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 {
|
||||
<[u8; RING_CONTEXT_SERIALIZED_MAX_SIZE]>::max_encoded_len()
|
||||
ring_context_serialized_size(D)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeInfo for RingContext {
|
||||
type Identity = [u8; RING_CONTEXT_SERIALIZED_MAX_SIZE];
|
||||
impl<const D: u32> TypeInfo for RingContext<D> {
|
||||
type Identity = Self;
|
||||
|
||||
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 {
|
||||
use super::{ring_vrf::*, vrf::*, *};
|
||||
use crate::crypto::{VrfPublic, VrfSecret, DEV_PHRASE};
|
||||
|
||||
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)]
|
||||
fn b2h(bytes: &[u8]) -> String {
|
||||
@@ -916,10 +923,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn backend_assumptions_sanity_check() {
|
||||
let kzg = KZG::testing_kzg_setup([0; 32], RING_DOMAIN_MAX_SIZE);
|
||||
assert_eq!(kzg.max_keyset_size() as u32, RING_MAX_SIZE);
|
||||
let kzg = KZG::testing_kzg_setup([0; 32], TEST_DOMAIN_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)
|
||||
.map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into())
|
||||
@@ -1071,7 +1078,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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();
|
||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||
@@ -1097,7 +1104,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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 pair = Pair::from_seed(DEV_SEED);
|
||||
@@ -1116,7 +1123,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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();
|
||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||
@@ -1145,7 +1152,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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();
|
||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||
@@ -1177,13 +1184,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn encode_decode_ring_vrf_context() {
|
||||
let ctx1 = RingContext::new_testing();
|
||||
let ctx1 = TestRingContext::new_testing();
|
||||
let enc1 = ctx1.encode();
|
||||
|
||||
assert_eq!(enc1.len(), RING_CONTEXT_SERIALIZED_MAX_SIZE);
|
||||
assert_eq!(RingContext::max_encoded_len(), RING_CONTEXT_SERIALIZED_MAX_SIZE);
|
||||
let _ti = <TestRingContext as TypeInfo>::type_info();
|
||||
|
||||
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();
|
||||
|
||||
assert_eq!(enc1, enc2);
|
||||
@@ -1191,7 +1200,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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();
|
||||
assert!(pks.len() <= ring_ctx.max_keyset_size());
|
||||
|
||||
Reference in New Issue
Block a user