Fully document crypto/

This commit is contained in:
Luke Parker
2023-03-20 20:10:00 -04:00
parent e1bb2c191b
commit 8d4d630e0f
45 changed files with 335 additions and 208 deletions

View File

@@ -13,9 +13,10 @@ This library offers ciphersuites compatible with the
11 is supported.
This library was
[audited by Cypher Stack in March 2023](https://github.com/serai-dex/serai/raw/74924095e1a0f266b58181b539d9e74fa35dc37a/audits/Cypher%20Stack%20crypto%20March%202023/Audit.pdf),
culminating in commit 669d2dbffc1dafb82a09d9419ea182667115df06. Any subsequent
changes have not undergone auditing. While this audit included FROST's
definition of Ed448, the underlying Ed448 ciphersuite (offered by the
[audited by Cypher Stack in March 2023](https://github.com/serai-dex/serai/raw/e1bb2c191b7123fd260d008e31656d090d559d21/audits/Cypher%20Stack%20crypto%20March%202023/Audit.pdf),
culminating in commit
[669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06).
Any subsequent changes have not undergone auditing. While this audit included
FROST's definition of Ed448, the underlying Ed448 ciphersuite (offered by the
ciphersuite crate) was not audited, nor was the minimal-ed448 crate implementing
the curve itself.

View File

@@ -22,6 +22,7 @@ macro_rules! dalek_curve {
const CONTEXT: &'static [u8] = $CONTEXT;
}
/// The challenge function for this ciphersuite.
#[derive(Copy, Clone)]
pub struct $Hram;
impl Hram<$Curve> for $Hram {

View File

@@ -11,11 +11,12 @@ impl Curve for Ed448 {
const CONTEXT: &'static [u8] = CONTEXT;
}
// The RFC-8032 Ed448 challenge function.
#[derive(Copy, Clone)]
pub struct Ietf8032Ed448Hram;
pub(crate) struct Ietf8032Ed448Hram;
impl Ietf8032Ed448Hram {
#[allow(non_snake_case)]
pub fn hram(context: &[u8], R: &Point, A: &Point, m: &[u8]) -> Scalar {
pub(crate) fn hram(context: &[u8], R: &Point, A: &Point, m: &[u8]) -> Scalar {
Scalar::wide_reduce(
Shake256_114::digest(
[
@@ -32,6 +33,7 @@ impl Ietf8032Ed448Hram {
}
}
/// The challenge function for FROST's Ed448 ciphersuite.
#[derive(Copy, Clone)]
pub struct IetfEd448Hram;
impl Hram<Ed448> for IetfEd448Hram {

View File

@@ -17,6 +17,7 @@ macro_rules! kp_curve {
const CONTEXT: &'static [u8] = $CONTEXT;
}
/// The challenge function for this ciphersuite.
#[derive(Clone)]
pub struct $Hram;
impl Hram<$Curve> for $Hram {

View File

@@ -33,10 +33,14 @@ pub use kp256::{P256, IetfP256Hram};
#[cfg(feature = "ed448")]
mod ed448;
#[cfg(feature = "ed448")]
pub use ed448::{Ed448, Ietf8032Ed448Hram, IetfEd448Hram};
pub use ed448::{Ed448, IetfEd448Hram};
#[cfg(all(test, feature = "ed448"))]
pub(crate) use ed448::Ietf8032Ed448Hram;
/// FROST Ciphersuite, except for the signing algorithm specific H2, making this solely the curve,
/// its associated hash function, and the functions derived from it.
/// FROST Ciphersuite.
///
/// This exclude the signing algorithm specific H2, making this solely the curve, its associated
/// hash function, and the functions derived from it.
pub trait Curve: Ciphersuite {
/// Context string for this curve.
const CONTEXT: &'static [u8];
@@ -98,6 +102,7 @@ pub trait Curve: Ciphersuite {
res
}
/// Read a point from a reader, rejecting identity.
#[allow(non_snake_case)]
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
let res = <Self as Ciphersuite>::read_G(reader)?;

View File

@@ -1,17 +1,5 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
//! A modular implementation of FROST for any curve with a ff/group API.
//! Additionally, custom algorithms may be specified so any signature reducible to
//! Schnorr-like may be used with FROST.
//!
//! A Schnorr algorithm is provided, of the form (R, s) where `s = r + cx`, which
//! allows specifying the challenge format. This is intended to easily allow
//! integrating with existing systems.
//!
//! This library offers ciphersuites compatible with the
//! [IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version
//! 11 is supported.
#![doc = include_str!("../README.md")]
use core::fmt::Debug;
use std::collections::HashMap;
@@ -53,12 +41,9 @@ pub enum FrostError {
InvalidPreprocess(Participant),
#[error("invalid share (participant {0})")]
InvalidShare(Participant),
#[error("internal error ({0})")]
InternalError(&'static str),
}
// Validate a map of values to have the expected included participants
/// Validate a map of values to have the expected participants.
pub fn validate_map<T>(
map: &HashMap<Participant, T>,
included: &[Participant],

View File

@@ -43,9 +43,9 @@ impl<T: Writable> Writable for Vec<T> {
}
}
/// Pairing of an Algorithm with a ThresholdKeys instance and this specific signing set.
// Pairing of an Algorithm with a ThresholdKeys instance.
#[derive(Clone, Zeroize)]
pub struct Params<C: Curve, A: Algorithm<C>> {
struct Params<C: Curve, A: Algorithm<C>> {
// Skips the algorithm due to being too large a bound to feasibly enforce on users
#[zeroize(skip)]
algorithm: A,
@@ -53,11 +53,11 @@ pub struct Params<C: Curve, A: Algorithm<C>> {
}
impl<C: Curve, A: Algorithm<C>> Params<C, A> {
pub fn new(algorithm: A, keys: ThresholdKeys<C>) -> Params<C, A> {
fn new(algorithm: A, keys: ThresholdKeys<C>) -> Params<C, A> {
Params { algorithm, keys }
}
pub fn multisig_params(&self) -> ThresholdParams {
fn multisig_params(&self) -> ThresholdParams {
self.keys.params()
}
}
@@ -66,6 +66,7 @@ impl<C: Curve, A: Algorithm<C>> Params<C, A> {
#[derive(Clone, PartialEq, Eq)]
pub struct Preprocess<C: Curve, A: Addendum> {
pub(crate) commitments: Commitments<C>,
/// The addendum used by the algorithm.
pub addendum: A,
}
@@ -76,9 +77,11 @@ impl<C: Curve, A: Addendum> Writable for Preprocess<C, A> {
}
}
/// A cached preprocess. A preprocess MUST only be used once. Reuse will enable third-party
/// recovery of your private key share. Additionally, this MUST be handled with the same security
/// as your private key share, as knowledge of it also enables recovery.
/// A cached preprocess.
///
/// A preprocess MUST only be used once. Reuse will enable third-party recovery of your private
/// key share. Additionally, this MUST be handled with the same security as your private key share,
/// as knowledge of it also enables recovery.
// Directly exposes the [u8; 32] member to void needing to route through std::io interfaces.
// Still uses Zeroizing internally so when users grab it, they have a higher likelihood of
// appreciating how to handle it and don't immediately start copying it just by grabbing it.
@@ -510,6 +513,6 @@ impl<C: Curve, A: Algorithm<C>> SignatureMachine<A::Signature> for AlgorithmSign
}
// If everyone has a valid share, and there were enough participants, this should've worked
Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid"))
panic!("everyone had a valid share yet the signature was still invalid");
}
}

View File

@@ -203,7 +203,7 @@ pub fn test_schnorr<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &mut R) {
assert!(sig.verify(group_key, H::hram(&sig.R, &group_key, MSG)));
}
// Test an offset Schnorr signature.
/// Test an offset Schnorr signature.
pub fn test_offset_schnorr<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &mut R) {
const MSG: &[u8] = b"Hello, World!";
@@ -223,7 +223,7 @@ pub fn test_offset_schnorr<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &m
assert!(sig.verify(offset_key, H::hram(&sig.R, &group_key, MSG)));
}
// Test blame for an invalid Schnorr signature share.
/// Test blame for an invalid Schnorr signature share.
pub fn test_schnorr_blame<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &mut R) {
const MSG: &[u8] = b"Hello, World!";
@@ -245,7 +245,7 @@ pub fn test_schnorr_blame<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &mu
}
}
// Run a variety of tests against a ciphersuite.
/// Run a variety of tests against a ciphersuite.
pub fn test_ciphersuite<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(rng: &mut R) {
test_schnorr::<R, C, H>(rng);
test_offset_schnorr::<R, C, H>(rng);

View File

@@ -22,6 +22,7 @@ use crate::{
tests::{clone_without, recover_key, test_ciphersuite},
};
/// Vectors for a ciphersuite.
pub struct Vectors {
pub threshold: u16,
@@ -141,6 +142,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<Participant,
keys
}
/// Test a Ciphersuite with its vectors.
pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
rng: &mut R,
vectors: Vectors,