mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 05:29:25 +00:00
Compare commits
9 Commits
ddbc32de4d
...
677a2e5749
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
677a2e5749 | ||
|
|
38bda1d586 | ||
|
|
2bc2ca6906 | ||
|
|
900a6612d7 | ||
|
|
17c1d5cd6b | ||
|
|
8a1b56a928 | ||
|
|
75964cf6da | ||
|
|
d407e35cee | ||
|
|
c8ef044acb |
15
Cargo.lock
generated
15
Cargo.lock
generated
@@ -1527,7 +1527,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ciphersuite"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"dalek-ff-group",
|
||||
"digest 0.10.7",
|
||||
@@ -1980,7 +1980,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dalek-ff-group"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
"curve25519-dalek",
|
||||
@@ -2698,14 +2698,13 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flexible-transcript"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"digest 0.10.7",
|
||||
"merlin",
|
||||
"rustversion",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"std-shims",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -5119,7 +5118,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "multiexp"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
dependencies = [
|
||||
"dalek-ff-group",
|
||||
"ff",
|
||||
@@ -7845,7 +7844,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schnorr-signatures"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
dependencies = [
|
||||
"ciphersuite",
|
||||
"dalek-ff-group",
|
||||
@@ -9692,7 +9691,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "std-shims"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"rustversion",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "std-shims"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
description = "A series of std shims to make alloc more feasible"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/common/std-shims"
|
||||
|
||||
@@ -26,7 +26,7 @@ blake2 = { version = "0.10", default-features = false, features = ["std"] }
|
||||
|
||||
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std", "recommended"] }
|
||||
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||
schnorr = { package = "schnorr-signatures", path = "../crypto/schnorr", default-features = false, features = ["std"] }
|
||||
schnorr = { package = "schnorr-signatures", path = "../crypto/schnorr", default-features = false, features = ["std", "aggregate"] }
|
||||
dkg-musig = { path = "../crypto/dkg/musig", default-features = false, features = ["std"] }
|
||||
frost = { package = "modular-frost", path = "../crypto/frost" }
|
||||
frost-schnorrkel = { path = "../crypto/schnorrkel" }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "ciphersuite"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
description = "Ciphersuites built around ff/group"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/ciphersuite"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["ciphersuite", "ff", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.66"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -24,7 +24,7 @@ rand_core = { version = "0.6", default-features = false }
|
||||
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
|
||||
subtle = { version = "^2.4", default-features = false }
|
||||
|
||||
digest = { version = "0.10", default-features = false }
|
||||
digest = { version = "0.10", default-features = false, features = ["core-api"] }
|
||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false }
|
||||
sha2 = { version = "0.10", default-features = false, optional = true }
|
||||
sha3 = { version = "0.10", default-features = false, optional = true }
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::fmt::Debug;
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
#[allow(unused_imports)]
|
||||
use std_shims::{
|
||||
prelude::*,
|
||||
io::{self, Read},
|
||||
};
|
||||
use std_shims::prelude::*;
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
use std_shims::io::{self, Read};
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "dalek-ff-group"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
description = "ff/group bindings around curve25519-dalek"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group"
|
||||
|
||||
@@ -17,7 +17,7 @@ use crypto_bigint::{
|
||||
impl_modulus,
|
||||
};
|
||||
|
||||
use group::ff::{Field, PrimeField, FieldBits, PrimeFieldBits};
|
||||
use group::ff::{Field, PrimeField, FieldBits, PrimeFieldBits, FromUniformBytes};
|
||||
|
||||
use crate::{u8_from_bool, constant_time, math_op, math};
|
||||
|
||||
@@ -311,6 +311,12 @@ impl FieldElement {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUniformBytes<64> for FieldElement {
|
||||
fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
|
||||
Self::wide_reduce(*bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sum<FieldElement> for FieldElement {
|
||||
fn sum<I: Iterator<Item = FieldElement>>(iter: I) -> FieldElement {
|
||||
let mut res = FieldElement::ZERO;
|
||||
|
||||
@@ -30,7 +30,7 @@ use dalek::{
|
||||
pub use constants::{ED25519_BASEPOINT_TABLE, RISTRETTO_BASEPOINT_TABLE};
|
||||
|
||||
use group::{
|
||||
ff::{Field, PrimeField, FieldBits, PrimeFieldBits},
|
||||
ff::{Field, PrimeField, FieldBits, PrimeFieldBits, FromUniformBytes},
|
||||
Group, GroupEncoding,
|
||||
prime::PrimeGroup,
|
||||
};
|
||||
@@ -322,6 +322,12 @@ impl PrimeFieldBits for Scalar {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUniformBytes<64> for Scalar {
|
||||
fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
|
||||
Self::from_bytes_mod_order_wide(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sum<Scalar> for Scalar {
|
||||
fn sum<I: Iterator<Item = Scalar>>(iter: I) -> Scalar {
|
||||
Self(DScalar::sum(iter))
|
||||
|
||||
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["dkg", "multisig", "threshold", "ff", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.66"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/dealer"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["dkg", "multisig", "threshold", "ff", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.66"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/recover
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["dkg", "multisig", "threshold", "ff", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.66"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "multiexp"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
description = "Multiexponentiation algorithms for ff/group"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/multiexp"
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{multiexp, multiexp_vartime};
|
||||
// Flatten the contained statements to a single Vec.
|
||||
// Wrapped in Zeroizing in case any of the included statements contain private values.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn flat<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>(
|
||||
fn flat<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||
slice: &[(Id, Vec<(G::Scalar, G)>)],
|
||||
) -> Zeroizing<Vec<(G::Scalar, G)>> {
|
||||
Zeroizing::new(slice.iter().flat_map(|pairs| pairs.1.iter()).copied().collect::<Vec<_>>())
|
||||
@@ -21,11 +21,11 @@ fn flat<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize
|
||||
/// A batch verifier intended to verify a series of statements are each equivalent to zero.
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone, Zeroize)]
|
||||
pub struct BatchVerifier<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>(
|
||||
pub struct BatchVerifier<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||
Zeroizing<Vec<(Id, Vec<(G::Scalar, G)>)>>,
|
||||
);
|
||||
|
||||
impl<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>
|
||||
impl<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>
|
||||
BatchVerifier<Id, G>
|
||||
{
|
||||
/// Create a new batch verifier, expected to verify the following amount of statements.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
#[allow(unused_imports)]
|
||||
use std_shims::prelude::*;
|
||||
use std_shims::vec::Vec;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
@@ -175,7 +177,9 @@ fn algorithm(len: usize) -> Algorithm {
|
||||
|
||||
/// Performs a multiexponentiation, automatically selecting the optimal algorithm based on the
|
||||
/// amount of pairs.
|
||||
pub fn multiexp<G: Group<Scalar: PrimeFieldBits + Zeroize>>(pairs: &[(G::Scalar, G)]) -> G {
|
||||
pub fn multiexp<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||
pairs: &[(G::Scalar, G)],
|
||||
) -> G {
|
||||
match algorithm(pairs.len()) {
|
||||
Algorithm::Null => Group::identity(),
|
||||
Algorithm::Single => pairs[0].1 * pairs[0].0,
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::prep_bits;
|
||||
|
||||
// Pippenger's algorithm for multiexponentiation, as published in the SIAM Journal on Computing
|
||||
// DOI: 10.1137/0209022
|
||||
pub(crate) fn pippenger<G: Group<Scalar: PrimeFieldBits>>(
|
||||
pub(crate) fn pippenger<G: Zeroize + Group<Scalar: PrimeFieldBits>>(
|
||||
pairs: &[(G::Scalar, G)],
|
||||
window: u8,
|
||||
) -> G {
|
||||
@@ -31,6 +31,8 @@ pub(crate) fn pippenger<G: Group<Scalar: PrimeFieldBits>>(
|
||||
intermediate_sum += buckets[b];
|
||||
res += intermediate_sum;
|
||||
}
|
||||
|
||||
buckets.zeroize();
|
||||
}
|
||||
|
||||
bits.zeroize();
|
||||
|
||||
@@ -24,12 +24,12 @@ fn prep_tables<G: Group>(pairs: &[(G::Scalar, G)], window: u8) -> Vec<Vec<G>> {
|
||||
|
||||
// Straus's algorithm for multiexponentiation, as published in The American Mathematical Monthly
|
||||
// DOI: 10.2307/2310929
|
||||
pub(crate) fn straus<G: Group<Scalar: PrimeFieldBits + Zeroize>>(
|
||||
pub(crate) fn straus<G: Zeroize + Group<Scalar: PrimeFieldBits>>(
|
||||
pairs: &[(G::Scalar, G)],
|
||||
window: u8,
|
||||
) -> G {
|
||||
let mut groupings = prep_bits(pairs, window);
|
||||
let tables = prep_tables(pairs, window);
|
||||
let mut tables = prep_tables(pairs, window);
|
||||
|
||||
let mut res = G::identity();
|
||||
for b in (0 .. groupings[0].len()).rev() {
|
||||
@@ -45,6 +45,7 @@ pub(crate) fn straus<G: Group<Scalar: PrimeFieldBits + Zeroize>>(
|
||||
}
|
||||
|
||||
groupings.zeroize();
|
||||
tables.zeroize();
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use group::Group;
|
||||
|
||||
use crate::BatchVerifier;
|
||||
|
||||
pub(crate) fn test_batch<G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>() {
|
||||
pub(crate) fn test_batch<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>() {
|
||||
let valid = |batch: BatchVerifier<_, G>| {
|
||||
assert!(batch.verify());
|
||||
assert!(batch.verify_vartime());
|
||||
|
||||
@@ -18,7 +18,7 @@ mod batch;
|
||||
use batch::test_batch;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn benchmark_internal<G: Group<Scalar: PrimeFieldBits + Zeroize>>(straus_bool: bool) {
|
||||
fn benchmark_internal<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(straus_bool: bool) {
|
||||
let runs: usize = 20;
|
||||
|
||||
let mut start = 0;
|
||||
@@ -83,7 +83,7 @@ fn benchmark_internal<G: Group<Scalar: PrimeFieldBits + Zeroize>>(straus_bool: b
|
||||
}
|
||||
}
|
||||
|
||||
fn test_multiexp<G: Group<Scalar: PrimeFieldBits + Zeroize>>() {
|
||||
fn test_multiexp<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>() {
|
||||
let test = |pairs: &[_], sum| {
|
||||
// These should automatically determine the best algorithm
|
||||
assert_eq!(multiexp(pairs), sum);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "schnorr-signatures"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
description = "Minimal Schnorr signatures crate hosting common code"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/schnorr"
|
||||
@@ -23,7 +23,7 @@ rand_core = { version = "0.6", default-features = false }
|
||||
|
||||
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||
|
||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false }
|
||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, optional = true }
|
||||
|
||||
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["alloc"] }
|
||||
multiexp = { path = "../multiexp", version = "0.4", default-features = false, features = ["batch"] }
|
||||
@@ -39,5 +39,6 @@ dalek-ff-group = { path = "../dalek-ff-group" }
|
||||
ciphersuite = { path = "../ciphersuite", features = ["ed25519"] }
|
||||
|
||||
[features]
|
||||
std = ["std-shims/std", "rand_core/std", "zeroize/std", "transcript/std", "ciphersuite/std", "multiexp/std"]
|
||||
aggregate = ["transcript"]
|
||||
std = ["std-shims/std", "rand_core/std", "zeroize/std", "transcript?/std", "ciphersuite/std", "multiexp/std"]
|
||||
default = ["std"]
|
||||
|
||||
@@ -25,6 +25,7 @@ use ciphersuite::{
|
||||
use multiexp::{multiexp_vartime, BatchVerifier};
|
||||
|
||||
/// Half-aggregation from <https://eprint.iacr.org/2021/350>.
|
||||
#[cfg(feature = "aggregate")]
|
||||
pub mod aggregate;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -9,10 +9,9 @@ use ciphersuite::{
|
||||
};
|
||||
use multiexp::BatchVerifier;
|
||||
|
||||
use crate::{
|
||||
SchnorrSignature,
|
||||
aggregate::{SchnorrAggregator, SchnorrAggregate},
|
||||
};
|
||||
use crate::SchnorrSignature;
|
||||
#[cfg(feature = "aggregate")]
|
||||
use crate::aggregate::{SchnorrAggregator, SchnorrAggregate};
|
||||
|
||||
mod rfc8032;
|
||||
|
||||
@@ -77,6 +76,7 @@ pub(crate) fn batch_verify<C: Ciphersuite>() {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "aggregate")]
|
||||
pub(crate) fn aggregate<C: Ciphersuite>() {
|
||||
const DST: &[u8] = b"Schnorr Aggregator Test";
|
||||
|
||||
@@ -117,5 +117,6 @@ fn test() {
|
||||
sign::<Ed25519>();
|
||||
verify::<Ed25519>();
|
||||
batch_verify::<Ed25519>();
|
||||
#[cfg(feature = "aggregate")]
|
||||
aggregate::<Ed25519>();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "flexible-transcript"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
description = "A simple transcript trait definition, along with viable options"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/transcript"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["transcript"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.66"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -17,9 +17,8 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
rustversion = "1"
|
||||
std-shims = { path = "../../common/std-shims", version = "0.1.4", default-features = false }
|
||||
|
||||
subtle = { version = "^2.4", default-features = false }
|
||||
zeroize = { version = "^1.5", default-features = false }
|
||||
|
||||
digest = { version = "0.10", default-features = false, features = ["core-api"] }
|
||||
@@ -32,8 +31,7 @@ sha2 = { version = "0.10", default-features = false }
|
||||
blake2 = { version = "0.10", default-features = false }
|
||||
|
||||
[features]
|
||||
std = ["subtle/std", "zeroize/std", "digest/std", "blake2?/std", "merlin?/std"]
|
||||
std = ["std-shims/std", "zeroize/std", "digest/std", "blake2?/std", "merlin?/std"]
|
||||
recommended = ["blake2"]
|
||||
merlin = ["dep:merlin"]
|
||||
tests = []
|
||||
default = ["std"]
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![no_std]
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std_shims::prelude::*;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use digest::{
|
||||
@@ -159,35 +162,12 @@ where
|
||||
// These writes may be optimized out if they're never read
|
||||
// Attempt to get them marked as read
|
||||
|
||||
#[rustversion::since(1.66)]
|
||||
fn mark_read<D: Send + Clone + SecureDigest>(transcript: &DigestTranscript<D>) {
|
||||
// Just get a challenge from the state
|
||||
let mut challenge = core::hint::black_box(transcript.0.clone().finalize());
|
||||
challenge.as_mut().zeroize();
|
||||
}
|
||||
|
||||
#[rustversion::before(1.66)]
|
||||
fn mark_read<D: Send + Clone + SecureDigest>(transcript: &mut DigestTranscript<D>) {
|
||||
// Get a challenge
|
||||
let challenge = transcript.0.clone().finalize();
|
||||
|
||||
// Attempt to use subtle's, non-exposed black_box function, by creating a Choice from this
|
||||
// challenge
|
||||
|
||||
let mut read = 0;
|
||||
for byte in challenge.as_ref() {
|
||||
read ^= byte;
|
||||
}
|
||||
challenge.as_mut().zeroize();
|
||||
|
||||
// Since this Choice isn't further read, its creation may be optimized out, including its
|
||||
// internal black_box
|
||||
// This remains our best attempt
|
||||
let mut choice = bool::from(subtle::Choice::from(read >> 7));
|
||||
read.zeroize();
|
||||
choice.zeroize();
|
||||
}
|
||||
|
||||
mark_read(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::Transcript;
|
||||
|
||||
/// Test the sanity of a transcript.
|
||||
///
|
||||
/// This will panic if sanity checks fail.
|
||||
pub fn test_transcript<T: Transcript<Challenge: PartialEq>>() {
|
||||
// Ensure distinct names cause distinct challenges
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user