Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ spin = { version = "0.9", default-features = false, features = ["once"], optiona
[dev-dependencies]
rand = { version = "0.8", features = ["getrandom"] }
rand_core = "0.6"
paste = "1.0"

[[example]]
name = "generate_test_keys"
Expand All @@ -40,8 +41,12 @@ std = [
"ark-serialize/std",
"ark-scale/std",
"ark-vrf/std",
"ark-vrf/parallel"
"ark-vrf/parallel",
]
# Include ring builder params binary data for building ring commitments.
# Disable this feature to reduce library size in production environments
# that only need to validate proofs (not build new ring commitments).
builder-params = []
schnorrkel = ["dep:schnorrkel"]
# Small ring 255, default to 16127
small-ring = []
Expand Down
48 changes: 38 additions & 10 deletions src/demo_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ use bounded_collections::{BoundedVec, ConstU32};
#[cfg(feature = "schnorrkel")]
use schnorrkel::{signing_context, ExpansionMode, MiniSecretKey, PublicKey};

/// Unit type implements Capacity for demo implementations that don't use ring VRF.
impl Capacity for () {
fn size(&self) -> usize {
1024
}
}

// Example impls:

/// Totally insecure Anonymizer: Member and Secret are both the same `[u8; 32]` and the proof is
Expand All @@ -19,12 +26,13 @@ impl GenerateVerifiable for Trivial {
type Proof = [u8; 32];
type Signature = [u8; 32];
type StaticChunk = ();
type Capacity = ();

fn is_member_valid(_member: &Self::Member) -> bool {
true
}

fn start_members() -> Self::Intermediate {
fn start_members(_capacity: ()) -> Self::Intermediate {
BoundedVec::new()
}

Expand All @@ -50,7 +58,9 @@ impl GenerateVerifiable for Trivial {
secret.clone()
}

#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn open(
_capacity: (),
member: &Self::Member,
members: impl Iterator<Item = Self::Member>,
) -> Result<Self::Commitment, ()> {
Expand All @@ -61,6 +71,7 @@ impl GenerateVerifiable for Trivial {
Ok((member.clone(), set))
}

#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn create(
(member, _): Self::Commitment,
secret: &Self::Secret,
Expand All @@ -74,6 +85,7 @@ impl GenerateVerifiable for Trivial {
}

fn validate(
_capacity: (),
proof: &Self::Proof,
members: &Self::Members,
_context: &[u8],
Expand Down Expand Up @@ -122,12 +134,13 @@ impl GenerateVerifiable for Simple {
type Proof = ([u8; 64], Alias);
type Signature = [u8; 64];
type StaticChunk = ();
type Capacity = ();

fn is_member_valid(_member: &Self::Member) -> bool {
true
}

fn start_members() -> Self::Intermediate {
fn start_members(_capacity: ()) -> Self::Intermediate {
BoundedVec::new()
}

Expand Down Expand Up @@ -155,7 +168,9 @@ impl GenerateVerifiable for Simple {
pair.public.to_bytes()
}

#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn open(
_capacity: (),
member: &Self::Member,
members: impl Iterator<Item = Self::Member>,
) -> Result<Self::Commitment, ()> {
Expand All @@ -166,6 +181,7 @@ impl GenerateVerifiable for Simple {
Ok((member.clone(), set))
}

#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn create(
(member, _): Self::Commitment,
secret: &Self::Secret,
Expand All @@ -186,6 +202,7 @@ impl GenerateVerifiable for Simple {
}

fn validate(
_capacity: (),
proof: &Self::Proof,
members: &Self::Members,
context: &[u8],
Expand Down Expand Up @@ -231,7 +248,10 @@ impl GenerateVerifiable for Simple {
mod tests {
use super::*;

#[cfg(feature = "schnorrkel")]
#[cfg(all(
feature = "schnorrkel",
any(feature = "std", feature = "no-std-prover")
))]
#[test]
fn simple_works() {
let alice_sec = <Simple as GenerateVerifiable>::new_secret([0u8; 32]);
Expand All @@ -240,15 +260,15 @@ mod tests {
let alice = <Simple as GenerateVerifiable>::member_from_secret(&alice_sec);
let bob = <Simple as GenerateVerifiable>::member_from_secret(&bob_sec);

let mut inter = <Simple as GenerateVerifiable>::start_members();
let mut inter = <Simple as GenerateVerifiable>::start_members(());
<Simple as GenerateVerifiable>::push_members(
&mut inter,
[alice.clone()].into_iter(),
|_| Ok(vec![()]),
|_| Ok(alloc::vec![()]),
)
.unwrap();
<Simple as GenerateVerifiable>::push_members(&mut inter, [bob.clone()].into_iter(), |_| {
Ok(vec![()])
Ok(alloc::vec![()])
})
.unwrap();
let members = <Simple as GenerateVerifiable>::finish_members(inter);
Expand All @@ -258,23 +278,31 @@ mod tests {
let message = b"Hello world";

let r = SimpleReceipt::create(
(),
&alice_sec,
members.iter().cloned(),
context,
message.to_vec(),
)
.unwrap();
let (alias, msg) = r.verify(&members, &context).unwrap();
let (alias, msg) = r.verify((), &members, context).unwrap();
assert_eq!(&message[..], &msg[..]);
assert_eq!(alias, alice);

let r = SimpleReceipt::create(&bob_sec, members.iter().cloned(), context, message.to_vec())
.unwrap();
let (alias, msg) = r.verify(&members, &context).unwrap();
let r = SimpleReceipt::create(
(),
&bob_sec,
members.iter().cloned(),
context,
message.to_vec(),
)
.unwrap();
let (alias, msg) = r.verify((), &members, context).unwrap();
assert_eq!(&message[..], &msg[..]);
assert_eq!(alias, bob);

assert!(SimpleReceipt::create(
(),
&charlie_sec,
members.iter().cloned(),
context,
Expand Down
52 changes: 44 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ use scale_info::*;
pub mod demo_impls;
pub mod ring_vrf_impl;

/// Trait for capacity types used in ring operations.
///
/// The capacity determines the maximum ring size that can be supported.
pub trait Capacity: Clone + Copy {
/// Returns the maximum ring size for this capacity.
fn size(&self) -> usize;
}

// Fixed types:

/// Cryptographic identifier for a person within a specific application which deals with people.
Expand Down Expand Up @@ -70,8 +78,12 @@ pub trait GenerateVerifiable {

type StaticChunk: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen;

/// The capacity type used to parametrize ring operations.
/// Must implement the `Capacity` trait which provides `size()`.
type Capacity: Clone + Copy + Capacity;

/// Begin building a `Members` value.
fn start_members() -> Self::Intermediate;
fn start_members(capacity: Self::Capacity) -> Self::Intermediate;

/// Introduce a set of new `Member`s into the intermediate value used to build a new `Members`
/// value.
Expand Down Expand Up @@ -110,7 +122,9 @@ pub trait GenerateVerifiable {
///
/// **WARNING**: This function may panic if called from on-chain or an environment not
/// implementing the functionality.
#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn open(
capacity: Self::Capacity,
member: &Self::Member,
members_iter: impl Iterator<Item = Self::Member>,
) -> Result<Self::Commitment, ()>;
Expand All @@ -130,6 +144,7 @@ pub trait GenerateVerifiable {
///
/// **WARNING**: This function may panic if called from on-chain or an environment not
/// implementing the functionality.
#[cfg(any(feature = "std", feature = "no-std-prover"))]
fn create(
commitment: Self::Commitment,
secret: &Self::Secret,
Expand All @@ -146,13 +161,14 @@ pub trait GenerateVerifiable {
/// if so, ensure that the member is necessarily associated with `alias` in this `context` and
/// that they elected to opine `message`.
fn is_valid(
capacity: Self::Capacity,
proof: &Self::Proof,
members: &Self::Members,
context: &[u8],
alias: &Alias,
message: &[u8],
) -> bool {
match Self::validate(proof, members, context, message) {
match Self::validate(capacity, proof, members, context, message) {
Ok(a) => &a == alias,
Err(()) => false,
}
Expand All @@ -163,6 +179,7 @@ pub trait GenerateVerifiable {

/// Like `is_valid`, but `alias` is returned, not provided.
fn validate(
_capacity: Self::Capacity,
_proof: &Self::Proof,
_members: &Self::Members,
_context: &[u8],
Expand Down Expand Up @@ -191,7 +208,9 @@ pub struct Receipt<Gen: GenerateVerifiable> {
}

impl<Gen: GenerateVerifiable> Receipt<Gen> {
#[cfg(any(feature = "std", feature = "no-std-prover"))]
pub fn create<'a>(
capacity: Gen::Capacity,
secret: &Gen::Secret,
members: impl Iterator<Item = Gen::Member>,
context: &[u8],
Expand All @@ -200,7 +219,7 @@ impl<Gen: GenerateVerifiable> Receipt<Gen> {
where
Gen::Member: 'a,
{
let commitment = Gen::open(&Gen::member_from_secret(secret), members)?;
let commitment = Gen::open(capacity, &Gen::member_from_secret(secret), members)?;
let (proof, alias) = Gen::create(commitment, secret, context, &message)?;
Ok(Self {
proof,
Expand All @@ -217,19 +236,36 @@ impl<Gen: GenerateVerifiable> Receipt<Gen> {
pub fn into_parts(self) -> (Alias, Vec<u8>) {
(self.alias, self.message)
}
pub fn verify(self, members: &Gen::Members, context: &[u8]) -> Result<(Alias, Vec<u8>), Self> {
match Gen::validate(&self.proof, members, context, &self.message) {
pub fn verify(
self,
capacity: Gen::Capacity,
members: &Gen::Members,
context: &[u8],
) -> Result<(Alias, Vec<u8>), Self> {
match Gen::validate(capacity, &self.proof, members, context, &self.message) {
Ok(alias) => Ok((alias, self.message)),
Err(()) => {
if self.is_valid(members, context) {
if self.is_valid(capacity, members, context) {
Ok(self.into_parts())
} else {
Err(self)
}
}
}
}
pub fn is_valid(&self, members: &Gen::Members, context: &[u8]) -> bool {
Gen::is_valid(&self.proof, members, context, &self.alias, &self.message)
pub fn is_valid(
&self,
capacity: Gen::Capacity,
members: &Gen::Members,
context: &[u8],
) -> bool {
Gen::is_valid(
capacity,
&self.proof,
members,
context,
&self.alias,
&self.message,
)
}
}
Binary file added src/ring-data/ring-builder-domain12.bin
Binary file not shown.
Binary file added src/ring-data/ring-builder-params-domain12.bin
Binary file not shown.
Loading