#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#[cfg(all(
feature = "prover",
not(feature = "std"),
not(feature = "no-std-prover")
))]
compile_error!(
"`prover` on a no_std target requires the `no-std-prover` feature. Without it the ring \
prover has no randomness source for the zero-knowledge blinding and panics during proof \
generation."
);
extern crate alloc;
use alloc::vec::Vec;
use core::{fmt::Debug, ops::Range};
use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, FullCodec, MaxEncodedLen};
use scale_info::*;
use smallvec::SmallVec;
#[cfg(feature = "mock")]
pub mod mock;
pub mod ring;
pub trait DecodeUnchecked: Sized + Decode {
fn decode_unchecked<I: parity_scale_codec::Input>(
input: &mut I,
) -> Result<Self, parity_scale_codec::Error> {
Self::decode(input)
}
}
pub type Alias = [u8; 32];
pub type Entropy = [u8; 32];
pub const MAX_CONTEXTS: usize = 16;
const _: () = assert!(MAX_CONTEXTS <= u8::MAX as usize);
pub type ContextVec<T> = SmallVec<[T; 3]>;
pub type AliasVec = ContextVec<Alias>;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
InvalidMember,
SetFull,
LookupFailed,
NotInRing,
TooManyContexts,
ContextCountMismatch,
DecodeError,
VerificationFailed,
Unsupported,
}
#[derive(Clone)]
pub struct BatchProofItem<Proof, Members, Config> {
pub proof: Proof,
pub config: Config,
pub members: Members,
pub context: Vec<u8>,
pub message: Vec<u8>,
}
pub type BatchProofItemFor<V> = BatchProofItem<
<V as GenerateVerifiable>::Proof,
<V as GenerateVerifiable>::Members,
<V as GenerateVerifiable>::Config,
>;
pub trait GenerateVerifiable {
type Members: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen;
type Intermediate: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen;
type Member: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen;
type Secret: Clone;
type Commitment: FullCodec;
type Proof: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo;
type StaticChunk: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen;
type Signature: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo;
type Config: Clone + Copy;
fn start_members(config: Self::Config) -> Self::Intermediate;
fn push_members(
intermediate: &mut Self::Intermediate,
members: impl Iterator<Item = Self::Member>,
lookup: impl Fn(Range<usize>) -> Result<Vec<Self::StaticChunk>, ()>,
) -> Result<(), Error>;
fn finish_members(inter: Self::Intermediate) -> Self::Members;
fn new_secret(entropy: Entropy) -> Self::Secret;
fn member_from_secret(secret: &Self::Secret) -> Self::Member;
#[cfg(feature = "prover")]
fn open(
config: Self::Config,
member: &Self::Member,
members_iter: impl Iterator<Item = Self::Member>,
) -> Result<Self::Commitment, Error>;
#[cfg(feature = "prover")]
fn create(
commitment: Self::Commitment,
secret: &Self::Secret,
context: &[u8],
message: &[u8],
) -> Result<(Self::Proof, Alias), Error> {
let (proof, aliases) = Self::create_multi_context(commitment, secret, &[context], message)?;
Ok((proof, aliases[0]))
}
#[cfg(feature = "prover")]
fn create_multi_context(
commitment: Self::Commitment,
secret: &Self::Secret,
contexts: &[&[u8]],
message: &[u8],
) -> Result<(Self::Proof, AliasVec), Error>;
fn is_valid(
config: Self::Config,
proof: &Self::Proof,
members: &Self::Members,
context: &[u8],
alias: &Alias,
message: &[u8],
) -> bool {
match Self::validate(config, proof, members, context, message) {
Ok(a) => &a == alias,
Err(_) => false,
}
}
fn is_valid_multi_context(
config: Self::Config,
proof: &Self::Proof,
members: &Self::Members,
contexts: &[&[u8]],
aliases: &[Alias],
message: &[u8],
) -> bool {
match Self::validate_multi_context(config, proof, members, contexts, message) {
Ok(a) => a.as_slice() == aliases,
Err(_) => false,
}
}
fn alias_in_context(secret: &Self::Secret, context: &[u8]) -> Result<Alias, Error>;
fn validate(
config: Self::Config,
proof: &Self::Proof,
members: &Self::Members,
context: &[u8],
message: &[u8],
) -> Result<Alias, Error> {
let result = Self::validate_multi_context(config, proof, members, &[context], message)?;
Ok(result[0])
}
fn validate_multi_context(
config: Self::Config,
proof: &Self::Proof,
members: &Self::Members,
contexts: &[&[u8]],
message: &[u8],
) -> Result<AliasVec, Error>;
fn batch_validate(proofs: &[BatchProofItemFor<Self>]) -> Result<Vec<Alias>, Error> {
proofs
.iter()
.map(|item| {
Self::validate(
item.config,
&item.proof,
&item.members,
&item.context,
&item.message,
)
})
.collect()
}
fn batch_validate_per_item(proofs: &[BatchProofItemFor<Self>]) -> Vec<Result<Alias, Error>> {
proofs
.iter()
.map(|item| {
Self::validate(
item.config,
&item.proof,
&item.members,
&item.context,
&item.message,
)
})
.collect()
}
fn is_member_valid(member: &Self::Member) -> bool;
fn sign(secret: &Self::Secret, message: &[u8]) -> Result<Self::Signature, Error>;
fn verify_signature(signature: &Self::Signature, message: &[u8], member: &Self::Member)
-> bool;
}
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, DecodeWithMemTracking)]
pub struct Receipt<Gen: GenerateVerifiable> {
proof: Gen::Proof,
alias: Alias,
message: Vec<u8>,
}
impl<Gen: GenerateVerifiable> Receipt<Gen> {
#[cfg(feature = "prover")]
pub fn create<'a>(
config: Gen::Config,
secret: &Gen::Secret,
members: impl Iterator<Item = Gen::Member>,
context: &[u8],
message: Vec<u8>,
) -> Result<Self, Error>
where
Gen::Member: 'a,
{
let commitment = Gen::open(config, &Gen::member_from_secret(secret), members)?;
let (proof, alias) = Gen::create(commitment, secret, context, &message)?;
Ok(Self {
proof,
alias,
message,
})
}
pub fn alias(&self) -> &Alias {
&self.alias
}
pub fn message(&self) -> &[u8] {
&self.message
}
pub fn into_parts(self) -> (Alias, Vec<u8>) {
(self.alias, self.message)
}
pub fn verify(
self,
config: Gen::Config,
members: &Gen::Members,
context: &[u8],
) -> Result<(Alias, Vec<u8>), Self> {
match Gen::validate(config, &self.proof, members, context, &self.message) {
Ok(alias) => Ok((alias, self.message)),
Err(_) => Err(self),
}
}
pub fn is_valid(&self, config: Gen::Config, members: &Gen::Members, context: &[u8]) -> bool {
Gen::is_valid(
config,
&self.proof,
members,
context,
&self.alias,
&self.message,
)
}
}