Expand and correct documentation

This commit is contained in:
Luke Parker 2022-09-29 05:25:29 -04:00
parent 19cd609cba
commit ca091a5f04
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
18 changed files with 137 additions and 118 deletions

View file

@ -4,4 +4,16 @@ A modern Monero transaction library intended for usage in wallets. It prides
itself on accuracy, correctness, and removing common pit falls developers may itself on accuracy, correctness, and removing common pit falls developers may
face. face.
Threshold multisignature support is available via the `multisig` feature. monero-serai contains safety features, such as first-class acknowledgement of
the burning bug, yet also a high level API around creating transactions.
monero-serai also offers a FROST-based multisig, which is orders of magnitude
more performant than Monero's.
monero-serai was written for Serai, a decentralized exchange aiming to support
Monero. Despite this, monero-serai is intended to be a widely usable library,
accurate to Monero. monero-serai guarantees the functionality needed for Serai,
yet will not deprive functionality from other users, and may potentially leave
Serai's umbrella at some point.
Various legacy transaction formats are not currently implemented, yet
monero-serai is still increasing its support for various transaction types.

View file

@ -0,0 +1,5 @@
# Monero Generators
Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called
`hash_to_point` here, is included, as needed to generate generators.

View file

@ -1,3 +1,7 @@
//! Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
//! An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called
//! `hash_to_point` here, is included, as needed to generate generators.
use lazy_static::lazy_static; use lazy_static::lazy_static;
use tiny_keccak::{Hasher, Keccak}; use tiny_keccak::{Hasher, Keccak};

View file

@ -34,12 +34,17 @@ pub(crate) mod frost;
mod serialize; mod serialize;
/// RingCT structs and functionality.
pub mod ringct; pub mod ringct;
/// Transaction structs.
pub mod transaction; pub mod transaction;
/// Block structs.
pub mod block; pub mod block;
/// Monero daemon RPC interface.
pub mod rpc; pub mod rpc;
/// Wallet functionality, enabling scanning and sending transactions.
pub mod wallet; pub mod wallet;
#[cfg(test)] #[cfg(test)]

View file

@ -5,7 +5,9 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwar
pub(crate) mod hash_to_point; pub(crate) mod hash_to_point;
pub use hash_to_point::{raw_hash_to_point, hash_to_point}; pub use hash_to_point::{raw_hash_to_point, hash_to_point};
/// CLSAG struct, along with signing and verifying functionality.
pub mod clsag; pub mod clsag;
/// Bulletproofs(+) structs, along with proving and verifying functionality.
pub mod bulletproofs; pub mod bulletproofs;
use crate::{ use crate::{

View file

@ -13,6 +13,7 @@ use crate::{hash, hash_to_scalar, serialize::write_varint, transaction::Input};
mod extra; mod extra;
pub(crate) use extra::{PaymentId, ExtraField, Extra}; pub(crate) use extra::{PaymentId, ExtraField, Extra};
/// Address encoding and decoding functionality.
pub mod address; pub mod address;
use address::{Network, AddressType, AddressMeta, Address}; use address::{Network, AddressType, AddressMeta, Address};

View file

@ -167,7 +167,7 @@ macro_rules! from_uint {
}; };
} }
/// Wrapper around the dalek Scalar type /// Wrapper around the dalek Scalar type.
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Zeroize)] #[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Zeroize)]
pub struct Scalar(pub DScalar); pub struct Scalar(pub DScalar);
deref_borrow!(Scalar, DScalar); deref_borrow!(Scalar, DScalar);
@ -176,12 +176,12 @@ math_neg!(Scalar, Scalar, DScalar::add, DScalar::sub, DScalar::mul);
from_uint!(Scalar, DScalar); from_uint!(Scalar, DScalar);
impl Scalar { impl Scalar {
/// Perform wide reduction on a 64-byte array to create a Scalar without bias /// Perform wide reduction on a 64-byte array to create a Scalar without bias.
pub fn from_bytes_mod_order_wide(bytes: &[u8; 64]) -> Scalar { pub fn from_bytes_mod_order_wide(bytes: &[u8; 64]) -> Scalar {
Self(DScalar::from_bytes_mod_order_wide(bytes)) Self(DScalar::from_bytes_mod_order_wide(bytes))
} }
/// Derive a Scalar without bias from a digest via wide reduction /// Derive a Scalar without bias from a digest via wide reduction.
pub fn from_hash<D: Digest<OutputSize = U64>>(hash: D) -> Scalar { pub fn from_hash<D: Digest<OutputSize = U64>>(hash: D) -> Scalar {
let mut output = [0u8; 64]; let mut output = [0u8; 64];
output.copy_from_slice(&hash.finalize()); output.copy_from_slice(&hash.finalize());
@ -287,7 +287,7 @@ macro_rules! dalek_group {
$BASEPOINT_POINT: ident, $BASEPOINT_POINT: ident,
$BASEPOINT_TABLE: ident $BASEPOINT_TABLE: ident
) => { ) => {
/// Wrapper around the dalek Point type. For Ed25519, this is restricted to the prime subgroup /// Wrapper around the dalek Point type. For Ed25519, this is restricted to the prime subgroup.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct $Point(pub $DPoint); pub struct $Point(pub $DPoint);
deref_borrow!($Point, $DPoint); deref_borrow!($Point, $DPoint);
@ -355,7 +355,7 @@ macro_rules! dalek_group {
impl PrimeGroup for $Point {} impl PrimeGroup for $Point {}
/// Wrapper around the dalek Table type, offering efficient multiplication against the /// Wrapper around the dalek Table type, offering efficient multiplication against the
/// basepoint /// basepoint.
pub struct $Table(pub $DTable); pub struct $Table(pub $DTable);
deref_borrow!($Table, $DTable); deref_borrow!($Table, $DTable);
pub const $BASEPOINT_TABLE: $Table = $Table(constants::$BASEPOINT_TABLE); pub const $BASEPOINT_TABLE: $Table = $Table(constants::$BASEPOINT_TABLE);

View file

@ -277,11 +277,11 @@ where
/// Prove the cross-Group Discrete Log Equality for the points derived from the scalar created as /// Prove the cross-Group Discrete Log Equality for the points derived from the scalar created as
/// the output of the passed in Digest. Given the non-standard requirements to achieve /// the output of the passed in Digest. Given the non-standard requirements to achieve
/// uniformity, needing to be < 2^x instead of less than a prime moduli, this is the simplest way /// uniformity, needing to be < 2^x instead of less than a prime moduli, this is the simplest way
/// to safely and securely generate a Scalar, without risk of failure, nor bias /// to safely and securely generate a Scalar, without risk of failure, nor bias.
/// It also ensures a lack of determinable relation between keys, guaranteeing security in the /// It also ensures a lack of determinable relation between keys, guaranteeing security in the
/// currently expected use case for this, atomic swaps, where each swap leaks the key. Knowing /// currently expected use case for this, atomic swaps, where each swap leaks the key. Knowing
/// the relationship between keys would allow breaking all swaps after just one
pub fn prove<R: RngCore + CryptoRng, T: Clone + Transcript, D: Digest>( pub fn prove<R: RngCore + CryptoRng, T: Clone + Transcript, D: Digest>(
/// the relationship between keys would allow breaking all swaps after just one.
rng: &mut R, rng: &mut R,
transcript: &mut T, transcript: &mut T,
generators: (Generators<G0>, Generators<G1>), generators: (Generators<G0>, Generators<G1>),
@ -297,7 +297,7 @@ where
/// Prove the cross-Group Discrete Log Equality for the points derived from the scalar passed in, /// Prove the cross-Group Discrete Log Equality for the points derived from the scalar passed in,
/// failing if it's not mutually valid. This allows for rejection sampling externally derived /// failing if it's not mutually valid. This allows for rejection sampling externally derived
/// scalars until they're safely usable, as needed /// scalars until they're safely usable, as needed.
pub fn prove_without_bias<R: RngCore + CryptoRng, T: Clone + Transcript>( pub fn prove_without_bias<R: RngCore + CryptoRng, T: Clone + Transcript>(
rng: &mut R, rng: &mut R,
transcript: &mut T, transcript: &mut T,
@ -307,7 +307,7 @@ where
scalar_convert(f0).map(|f1| Self::prove_internal(rng, transcript, generators, (f0, f1))) scalar_convert(f0).map(|f1| Self::prove_internal(rng, transcript, generators, (f0, f1)))
} }
/// Verify a cross-Group Discrete Log Equality statement, returning the points proven for /// Verify a cross-Group Discrete Log Equality statement, returning the points proven for.
pub fn verify<R: RngCore + CryptoRng, T: Clone + Transcript>( pub fn verify<R: RngCore + CryptoRng, T: Clone + Transcript>(
&self, &self,
rng: &mut R, rng: &mut R,

View file

@ -2,7 +2,7 @@ use ff::PrimeFieldBits;
use zeroize::Zeroize; use zeroize::Zeroize;
/// Convert a uniform scalar into one usable on both fields, clearing the top bits as needed /// Convert a uniform scalar into one usable on both fields, clearing the top bits as needed.
pub fn scalar_normalize<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>( pub fn scalar_normalize<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>(
mut scalar: F0, mut scalar: F0,
) -> (F0, F1) { ) -> (F0, F1) {
@ -45,7 +45,7 @@ pub fn scalar_normalize<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>(
(res1, res2) (res1, res2)
} }
/// Helper to convert a scalar between fields. Returns None if the scalar isn't mutually valid /// Helper to convert a scalar between fields. Returns None if the scalar isn't mutually valid.
pub fn scalar_convert<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>( pub fn scalar_convert<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>(
mut scalar: F0, mut scalar: F0,
) -> Option<F1> { ) -> Option<F1> {
@ -56,7 +56,7 @@ pub fn scalar_convert<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>(
res res
} }
/// Create a mutually valid scalar from bytes via bit truncation to not introduce bias /// Create a mutually valid scalar from bytes via bit truncation to not introduce bias.
pub fn mutual_scalar_from_bytes<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>( pub fn mutual_scalar_from_bytes<F0: PrimeFieldBits + Zeroize, F1: PrimeFieldBits>(
bytes: &[u8], bytes: &[u8],
) -> (F0, F1) { ) -> (F0, F1) {

View file

@ -8,27 +8,27 @@ use transcript::Transcript;
use crate::{Curve, FrostError, FrostView, schnorr}; use crate::{Curve, FrostError, FrostView, schnorr};
pub use schnorr::SchnorrSignature; pub use schnorr::SchnorrSignature;
/// Algorithm to use FROST with /// Algorithm to use FROST with.
pub trait Algorithm<C: Curve>: Clone { pub trait Algorithm<C: Curve>: Clone {
type Transcript: Transcript + Clone + Debug; type Transcript: Transcript + Clone + Debug;
/// The resulting type of the signatures this algorithm will produce /// The resulting type of the signatures this algorithm will produce.
type Signature: Clone + PartialEq + Debug; type Signature: Clone + PartialEq + Debug;
/// Obtain a mutable borrow of the underlying transcript /// Obtain a mutable borrow of the underlying transcript.
fn transcript(&mut self) -> &mut Self::Transcript; fn transcript(&mut self) -> &mut Self::Transcript;
/// Obtain the list of nonces to generate, as specified by the basepoints to create commitments /// Obtain the list of nonces to generate, as specified by the basepoints to create commitments.
/// against per-nonce. These are not committed to by FROST on the underlying transcript /// against per-nonce. These are not committed to by FROST on the underlying transcript.
fn nonces(&self) -> Vec<Vec<C::G>>; fn nonces(&self) -> Vec<Vec<C::G>>;
/// Generate an addendum to FROST"s preprocessing stage /// Generate an addendum to FROST"s preprocessing stage.
fn preprocess_addendum<R: RngCore + CryptoRng>( fn preprocess_addendum<R: RngCore + CryptoRng>(
&mut self, &mut self,
rng: &mut R, rng: &mut R,
params: &FrostView<C>, params: &FrostView<C>,
) -> Vec<u8>; ) -> Vec<u8>;
/// Proccess the addendum for the specified participant. Guaranteed to be ordered /// Proccess the addendum for the specified participant. Guaranteed to be ordered.
fn process_addendum<Re: Read>( fn process_addendum<Re: Read>(
&mut self, &mut self,
params: &FrostView<C>, params: &FrostView<C>,
@ -36,10 +36,10 @@ pub trait Algorithm<C: Curve>: Clone {
reader: &mut Re, reader: &mut Re,
) -> Result<(), FrostError>; ) -> Result<(), FrostError>;
/// Sign a share with the given secret/nonce /// Sign a share with the given secret/nonce.
/// The secret will already have been its lagrange coefficient applied so it is the necessary /// The secret will already have been its lagrange coefficient applied so it is the necessary
/// key share /// key share.
/// The nonce will already have been processed into the combined form d + (e * p) /// The nonce will already have been processed into the combined form d + (e * p).
fn sign_share( fn sign_share(
&mut self, &mut self,
params: &FrostView<C>, params: &FrostView<C>,
@ -48,12 +48,12 @@ pub trait Algorithm<C: Curve>: Clone {
msg: &[u8], msg: &[u8],
) -> C::F; ) -> C::F;
/// Verify a signature /// Verify a signature.
#[must_use] #[must_use]
fn verify(&self, group_key: C::G, nonces: &[Vec<C::G>], sum: C::F) -> Option<Self::Signature>; fn verify(&self, group_key: C::G, nonces: &[Vec<C::G>], sum: C::F) -> Option<Self::Signature>;
/// Verify a specific share given as a response. Used to determine blame if signature /// Verify a specific share given as a response. Used to determine blame if signature
/// verification fails /// verification fails.
#[must_use] #[must_use]
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool; fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool;
} }
@ -84,8 +84,8 @@ impl Transcript for IetfTranscript {
} }
pub trait Hram<C: Curve>: Clone { pub trait Hram<C: Curve>: Clone {
/// HRAM function to generate a challenge /// HRAM function to generate a challenge.
/// H2 from the IETF draft despite having a different argument set (not pre-formatted) /// H2 from the IETF draft, despite having a different argument set (not being pre-formatted).
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F; fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F;
} }
@ -109,7 +109,7 @@ impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
} }
} }
/// Implementation of Schnorr signatures for use with FROST /// Implementation of Schnorr signatures for use with FROST.
impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> { impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
type Transcript = IetfTranscript; type Transcript = IetfTranscript;
type Signature = SchnorrSignature<C>; type Signature = SchnorrSignature<C>;

View file

@ -29,7 +29,7 @@ mod ed448;
#[cfg(feature = "ed448")] #[cfg(feature = "ed448")]
pub use ed448::{Ed448, Ietf8032Ed448Hram, NonIetfEd448Hram}; pub use ed448::{Ed448, Ietf8032Ed448Hram, NonIetfEd448Hram};
/// Set of errors for curve-related operations, namely encoding and decoding /// Set of errors for curve-related operations, namely encoding and decoding.
#[derive(Clone, Error, Debug)] #[derive(Clone, Error, Debug)]
pub enum CurveError { pub enum CurveError {
#[error("invalid scalar")] #[error("invalid scalar")]
@ -38,23 +38,23 @@ pub enum CurveError {
InvalidPoint, InvalidPoint,
} }
/// Unified trait to manage a field/group /// Unified trait to manage an elliptic curve.
// This should be moved into its own crate if the need for generic cryptography over ff/group // This should be moved into its own crate if the need for generic cryptography over ff/group
// continues, which is the exact reason ff/group exists (to provide a generic interface) // continues, which is the exact reason ff/group exists (to provide a generic interface)
// elliptic-curve exists, yet it doesn't really serve the same role, nor does it use &[u8]/Vec<u8> // elliptic-curve exists, yet it doesn't really serve the same role, nor does it use &[u8]/Vec<u8>
// It uses GenericArray which will hopefully be deprecated as Rust evolves and doesn't offer enough // It uses GenericArray which will hopefully be deprecated as Rust evolves and doesn't offer enough
// advantages in the modern day to be worth the hassle -- Kayaba // advantages in the modern day to be worth the hassle -- Kayaba
pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize { pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
/// Scalar field element type /// Scalar field element type.
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses // This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
type F: PrimeField + PrimeFieldBits + Zeroize; type F: PrimeField + PrimeFieldBits + Zeroize;
/// Group element type /// Group element type.
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize; type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize;
/// ID for this curve /// ID for this curve.
const ID: &'static [u8]; const ID: &'static [u8];
/// Generator for the group /// Generator for the group.
// While group does provide this in its API, privacy coins may want to use a custom basepoint // While group does provide this in its API, privacy coins may want to use a custom basepoint
fn generator() -> Self::G; fn generator() -> Self::G;
@ -66,22 +66,22 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F; fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
/// Hash the message for the binding factor. H4 from the IETF draft /// Hash the message for the binding factor. H4 from the IETF draft.
fn hash_msg(msg: &[u8]) -> Vec<u8> { fn hash_msg(msg: &[u8]) -> Vec<u8> {
Self::hash_to_vec(b"msg", msg) Self::hash_to_vec(b"msg", msg)
} }
/// Hash the commitments for the binding factor. H5 from the IETF draft /// Hash the commitments for the binding factor. H5 from the IETF draft.
fn hash_commitments(commitments: &[u8]) -> Vec<u8> { fn hash_commitments(commitments: &[u8]) -> Vec<u8> {
Self::hash_to_vec(b"com", commitments) Self::hash_to_vec(b"com", commitments)
} }
/// Hash the commitments and message to calculate the binding factor. H1 from the IETF draft /// Hash the commitments and message to calculate the binding factor. H1 from the IETF draft.
fn hash_binding_factor(binding: &[u8]) -> Self::F { fn hash_binding_factor(binding: &[u8]) -> Self::F {
Self::hash_to_F(b"rho", binding) Self::hash_to_F(b"rho", binding)
} }
/// Securely generate a random nonce. H3 from the IETF draft /// Securely generate a random nonce. H3 from the IETF draft.
fn random_nonce<R: RngCore + CryptoRng>(mut secret: Self::F, rng: &mut R) -> Self::F { fn random_nonce<R: RngCore + CryptoRng>(mut secret: Self::F, rng: &mut R) -> Self::F {
let mut seed = vec![0; 32]; let mut seed = vec![0; 32];
rng.fill_bytes(&mut seed); rng.fill_bytes(&mut seed);

View file

@ -178,10 +178,8 @@ fn generate_key_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
} }
/// Finishes round 2 and returns both the secret share and the serialized public key. /// Finishes round 2 and returns both the secret share and the serialized public key.
/// This key is not usable until all parties confirm they have completed the protocol without /// This key MUST NOT be considered usable until all parties confirm they have completed the
/// issue, yet simply confirming protocol completion without issue is enough to confirm the same /// protocol without issue.
/// key was generated as long as a lack of duplicated commitments was also confirmed when they were
/// broadcasted initially
fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>( fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
rng: &mut R, rng: &mut R,
params: FrostParams, params: FrostParams,
@ -291,15 +289,16 @@ impl<C: Curve> Drop for KeyMachine<C> {
impl<C: Curve> ZeroizeOnDrop for KeyMachine<C> {} impl<C: Curve> ZeroizeOnDrop for KeyMachine<C> {}
impl<C: Curve> KeyGenMachine<C> { impl<C: Curve> KeyGenMachine<C> {
/// Creates a new machine to generate a key for the specified curve in the specified multisig /// Creates a new machine to generate a key for the specified curve in the specified multisig.
// The context string must be unique among multisigs // The context string should be unique among multisigs.
pub fn new(params: FrostParams, context: String) -> KeyGenMachine<C> { pub fn new(params: FrostParams, context: String) -> KeyGenMachine<C> {
KeyGenMachine { params, context, _curve: PhantomData } KeyGenMachine { params, context, _curve: PhantomData }
} }
/// Start generating a key according to the FROST DKG spec /// Start generating a key according to the FROST DKG spec.
/// Returns a serialized list of commitments to be sent to all parties over an authenticated /// Returns a serialized list of commitments to be sent to all parties over an authenticated
/// channel. If any party submits multiple sets of commitments, they MUST be treated as malicious /// channel. If any party submits multiple sets of commitments, they MUST be treated as
/// malicious.
pub fn generate_coefficients<R: RngCore + CryptoRng>( pub fn generate_coefficients<R: RngCore + CryptoRng>(
self, self,
rng: &mut R, rng: &mut R,
@ -320,11 +319,9 @@ impl<C: Curve> KeyGenMachine<C> {
} }
impl<C: Curve> SecretShareMachine<C> { impl<C: Curve> SecretShareMachine<C> {
/// Continue generating a key /// Continue generating a key.
/// Takes in everyone else's commitments, which are expected to be in a Vec where participant /// Takes in everyone else's commitments. Returns a HashMap of byte vectors representing secret
/// index = Vec index. An empty vector is expected at index 0 to allow for this. An empty vector /// shares. These MUST be encrypted and only then sent to their respective participants.
/// is also expected at index i which is locally handled. Returns a byte vector representing a
/// secret share for each other participant which should be encrypted before sending
pub fn generate_secret_shares<Re: Read, R: RngCore + CryptoRng>( pub fn generate_secret_shares<Re: Read, R: RngCore + CryptoRng>(
mut self, mut self,
rng: &mut R, rng: &mut R,
@ -343,12 +340,10 @@ impl<C: Curve> SecretShareMachine<C> {
} }
impl<C: Curve> KeyMachine<C> { impl<C: Curve> KeyMachine<C> {
/// Complete key generation /// Complete key generation.
/// Takes in everyone elses' shares submitted to us as a Vec, expecting participant index = /// Takes in everyone elses' shares submitted to us. Returns a FrostCore object representing the
/// Vec index with an empty vector at index 0 and index i. Returns a byte vector representing the /// generated keys. Successful protocol completion MUST be confirmed by all parties before these
/// group's public key, while setting a valid secret share inside the machine. > t participants /// keys may be safely used.
/// must report completion without issue before this key can be considered usable, yet you should
/// wait for all participants to report as such
pub fn complete<Re: Read, R: RngCore + CryptoRng>( pub fn complete<Re: Read, R: RngCore + CryptoRng>(
mut self, mut self,
rng: &mut R, rng: &mut R,

View file

@ -51,15 +51,15 @@ pub(crate) fn validate_map<T>(
Ok(()) Ok(())
} }
/// Parameters for a multisig /// Parameters for a multisig.
// These fields can not be made public as they should be static // These fields can not be made public as they should be static
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct FrostParams { pub struct FrostParams {
/// Participants needed to sign on behalf of the group /// Participants needed to sign on behalf of the group.
t: u16, t: u16,
/// Amount of participants /// Amount of participants.
n: u16, n: u16,
/// Index of the participant being acted for /// Index of the participant being acted for.
i: u16, i: u16,
} }
@ -122,7 +122,7 @@ pub enum FrostError {
InternalError(&'static str), InternalError(&'static str),
} }
/// Calculate the lagrange coefficient for a signing set /// Calculate the lagrange coefficient for a signing set.
pub fn lagrange<F: PrimeField>(i: u16, included: &[u16]) -> F { pub fn lagrange<F: PrimeField>(i: u16, included: &[u16]) -> F {
let mut num = F::one(); let mut num = F::one();
let mut denom = F::one(); let mut denom = F::one();
@ -141,18 +141,18 @@ pub fn lagrange<F: PrimeField>(i: u16, included: &[u16]) -> F {
num * denom.invert().unwrap() num * denom.invert().unwrap()
} }
/// Core keys generated by performing a FROST keygen protocol /// Core keys generated by performing a FROST keygen protocol.
#[derive(Clone, PartialEq, Eq, Zeroize)] #[derive(Clone, PartialEq, Eq, Zeroize)]
pub struct FrostCore<C: Curve> { pub struct FrostCore<C: Curve> {
/// FROST Parameters /// FROST Parameters.
#[zeroize(skip)] #[zeroize(skip)]
params: FrostParams, params: FrostParams,
/// Secret share key /// Secret share key.
secret_share: C::F, secret_share: C::F,
/// Group key /// Group key.
group_key: C::G, group_key: C::G,
/// Verification shares /// Verification shares.
#[zeroize(skip)] #[zeroize(skip)]
verification_shares: HashMap<u16, C::G>, verification_shares: HashMap<u16, C::G>,
} }
@ -273,14 +273,14 @@ impl<C: Curve> FrostCore<C> {
} }
} }
/// FROST keys usable for signing /// FROST keys usable for signing.
#[derive(Clone, Debug, Zeroize)] #[derive(Clone, Debug, Zeroize)]
pub struct FrostKeys<C: Curve> { pub struct FrostKeys<C: Curve> {
/// Core keys /// Core keys.
#[zeroize(skip)] #[zeroize(skip)]
core: Arc<FrostCore<C>>, core: Arc<FrostCore<C>>,
/// Offset applied to these keys /// Offset applied to these keys.
pub(crate) offset: Option<C::F>, pub(crate) offset: Option<C::F>,
} }
@ -315,10 +315,10 @@ impl<C: Curve> FrostKeys<C> {
FrostKeys { core: Arc::new(core), offset: None } FrostKeys { core: Arc::new(core), offset: None }
} }
/// Offset the keys by a given scalar to allow for account and privacy schemes /// Offset the keys by a given scalar to allow for account and privacy schemes.
/// This offset is ephemeral and will not be included when these keys are serialized /// This offset is ephemeral and will not be included when these keys are serialized.
/// Keys offset multiple times will form a new offset of their sum /// Keys offset multiple times will form a new offset of their sum.
/// Not IETF compliant /// Not IETF compliant.
pub fn offset(&self, offset: C::F) -> FrostKeys<C> { pub fn offset(&self, offset: C::F) -> FrostKeys<C> {
let mut res = self.clone(); let mut res = self.clone();
// Carry any existing offset // Carry any existing offset
@ -336,12 +336,12 @@ impl<C: Curve> FrostKeys<C> {
self.core.secret_share self.core.secret_share
} }
/// Returns the group key with any offset applied /// Returns the group key with any offset applied.
pub fn group_key(&self) -> C::G { pub fn group_key(&self) -> C::G {
self.core.group_key + (C::generator() * self.offset.unwrap_or_else(C::F::zero)) self.core.group_key + (C::generator() * self.offset.unwrap_or_else(C::F::zero))
} }
/// Returns all participants' verification shares without any offsetting /// Returns all participants' verification shares without any offsetting.
pub(crate) fn verification_shares(&self) -> HashMap<u16, C::G> { pub(crate) fn verification_shares(&self) -> HashMap<u16, C::G> {
self.core.verification_shares() self.core.verification_shares()
} }

View file

@ -17,7 +17,7 @@ use crate::{
FrostError, FrostCore, FrostKeys, validate_map, FrostError, FrostCore, FrostKeys, validate_map,
}; };
/// Promote a set of keys to another Curve definition /// Promote a set of keys to another Curve definition.
pub trait CurvePromote<C2: Curve> { pub trait CurvePromote<C2: Curve> {
#[doc(hidden)] #[doc(hidden)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -86,7 +86,7 @@ pub struct GeneratorPromotion<C1: Curve, C2: Curve> {
_c2: PhantomData<C2>, _c2: PhantomData<C2>,
} }
/// Promote a set of keys from one generator to another /// Promote a set of keys from one generator to another.
// The linear DLEq proofs are much more efficient than an exponential key gen // The linear DLEq proofs are much more efficient than an exponential key gen
impl<C1: Curve, C2: Curve> GeneratorPromotion<C1, C2> impl<C1: Curve, C2: Curve> GeneratorPromotion<C1, C2>
where where

View file

@ -22,7 +22,7 @@ use crate::{
curve::Curve, FrostError, FrostParams, FrostKeys, FrostView, algorithm::Algorithm, validate_map, curve::Curve, FrostError, FrostParams, FrostKeys, FrostView, algorithm::Algorithm, validate_map,
}; };
/// Pairing of an Algorithm with a FrostKeys instance and this specific signing set /// Pairing of an Algorithm with a FrostKeys instance and this specific signing set.
#[derive(Clone)] #[derive(Clone)]
pub struct Params<C: Curve, A: Algorithm<C>> { pub struct Params<C: Curve, A: Algorithm<C>> {
algorithm: A, algorithm: A,
@ -369,20 +369,17 @@ pub trait PreprocessMachine {
type Signature: Clone + PartialEq + fmt::Debug; type Signature: Clone + PartialEq + fmt::Debug;
type SignMachine: SignMachine<Self::Signature>; type SignMachine: SignMachine<Self::Signature>;
/// Perform the preprocessing round required in order to sign /// Perform the preprocessing round required in order to sign.
/// Returns a byte vector which must be transmitted to all parties selected for this signing /// Returns a byte vector to be broadcast to all participants, over an authenticated channel.
/// process, over an authenticated channel
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>); fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>);
} }
pub trait SignMachine<S> { pub trait SignMachine<S> {
type SignatureMachine: SignatureMachine<S>; type SignatureMachine: SignatureMachine<S>;
/// Sign a message /// Sign a message.
/// Takes in the participant's commitments, which are expected to be in a Vec where participant /// Takes in the participants' preprocesses. Returns a byte vector representing a signature share
/// index = Vec index. None is expected at index 0 to allow for this. None is also expected at /// to be broadcast to all participants, over an authenticated channel.
/// index i which is locally handled. Returns a byte vector representing a share of the signature
/// for every other participant to receive, over an authenticated channel
fn sign<Re: Read>( fn sign<Re: Read>(
self, self,
commitments: HashMap<u16, Re>, commitments: HashMap<u16, Re>,
@ -391,14 +388,12 @@ pub trait SignMachine<S> {
} }
pub trait SignatureMachine<S> { pub trait SignatureMachine<S> {
/// Complete signing /// Complete signing.
/// Takes in everyone elses' shares submitted to us as a Vec, expecting participant index = /// Takes in everyone elses' shares. Returns the signature.
/// Vec index with None at index 0 and index i. Returns a byte vector representing the serialized
/// signature
fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<S, FrostError>; fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<S, FrostError>;
} }
/// State machine which manages signing for an arbitrary signature algorithm /// State machine which manages signing for an arbitrary signature algorithm.
pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> { pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
params: Params<C, A>, params: Params<C, A>,
} }
@ -414,7 +409,7 @@ pub struct AlgorithmSignatureMachine<C: Curve, A: Algorithm<C>> {
} }
impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> { impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> {
/// Creates a new machine to generate a key for the specified curve in the specified multisig /// Creates a new machine to generate a signature with the specified keys.
pub fn new( pub fn new(
algorithm: A, algorithm: A,
keys: FrostKeys<C>, keys: FrostKeys<C>,

View file

@ -11,22 +11,22 @@ use digest::{typenum::type_operators::IsGreaterOrEqual, consts::U256, Digest, Ou
pub trait Transcript { pub trait Transcript {
type Challenge: Clone + Send + Sync + AsRef<[u8]>; type Challenge: Clone + Send + Sync + AsRef<[u8]>;
/// Create a new transcript with the specified name /// Create a new transcript with the specified name.
fn new(name: &'static [u8]) -> Self; fn new(name: &'static [u8]) -> Self;
/// Apply a domain separator to the transcript /// Apply a domain separator to the transcript.
fn domain_separate(&mut self, label: &'static [u8]); fn domain_separate(&mut self, label: &'static [u8]);
/// Append a message to the transcript /// Append a message to the transcript.
fn append_message(&mut self, label: &'static [u8], message: &[u8]); fn append_message(&mut self, label: &'static [u8], message: &[u8]);
/// Produce a challenge. This MUST update the transcript as it does so, preventing the same /// Produce a challenge. This MUST update the transcript as it does so, preventing the same
/// challenge from being generated multiple times /// challenge from being generated multiple times.
fn challenge(&mut self, label: &'static [u8]) -> Self::Challenge; fn challenge(&mut self, label: &'static [u8]) -> Self::Challenge;
/// Produce a RNG seed. Helper function for parties needing to generate random data from an /// Produce a RNG seed. Helper function for parties needing to generate random data from an
/// agreed upon state. Internally calls the challenge function for the needed bytes, converting /// agreed upon state. Internally calls the challenge function for the needed bytes, converting
/// them to the seed format rand_core expects /// them to the seed format rand_core expects.
fn rng_seed(&mut self, label: &'static [u8]) -> [u8; 32]; fn rng_seed(&mut self, label: &'static [u8]) -> [u8; 32];
} }
@ -50,12 +50,12 @@ impl DigestTranscriptMember {
} }
} }
/// A trait defining Digests with at least a 256-byte output size, assuming at least a 128-bit
/// level of security accordingly
pub trait SecureDigest: Clone + Digest {} pub trait SecureDigest: Clone + Digest {}
impl<D: Clone + Digest> SecureDigest for D where D::OutputSize: IsGreaterOrEqual<U256> {} impl<D: Clone + Digest> SecureDigest for D where D::OutputSize: IsGreaterOrEqual<U256> {}
/// A trait defining cryptographic Digests with at least a 256-byte output size, assuming at least
/// a 128-bit level of security accordingly.
/// A simple transcript format constructed around the specified hash algorithm /// A simple transcript format constructed around the specified hash algorithm.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DigestTranscript<D: SecureDigest>(D); pub struct DigestTranscript<D: SecureDigest>(D);

View file

@ -11,35 +11,35 @@ pub struct Cli {
#[derive(Debug, clap::Subcommand)] #[derive(Debug, clap::Subcommand)]
pub enum Subcommand { pub enum Subcommand {
/// Key management CLI utilities // Key management CLI utilities
#[clap(subcommand)] #[clap(subcommand)]
Key(sc_cli::KeySubcommand), Key(sc_cli::KeySubcommand),
/// Build a chain specification // Build a chain specification
BuildSpec(sc_cli::BuildSpecCmd), BuildSpec(sc_cli::BuildSpecCmd),
/// Validate blocks // Validate blocks
CheckBlock(sc_cli::CheckBlockCmd), CheckBlock(sc_cli::CheckBlockCmd),
/// Export blocks // Export blocks
ExportBlocks(sc_cli::ExportBlocksCmd), ExportBlocks(sc_cli::ExportBlocksCmd),
/// Export the state of a given block into a chain spec // Export the state of a given block into a chain spec
ExportState(sc_cli::ExportStateCmd), ExportState(sc_cli::ExportStateCmd),
/// Import blocks // Import blocks
ImportBlocks(sc_cli::ImportBlocksCmd), ImportBlocks(sc_cli::ImportBlocksCmd),
/// Remove the entire chain // Remove the entire chain
PurgeChain(sc_cli::PurgeChainCmd), PurgeChain(sc_cli::PurgeChainCmd),
/// Revert the chain to a previous state // Revert the chain to a previous state
Revert(sc_cli::RevertCmd), Revert(sc_cli::RevertCmd),
/// Sub-commands concerned with benchmarking // Sub-commands concerned with benchmarking
#[clap(subcommand)] #[clap(subcommand)]
Benchmark(frame_benchmarking_cli::BenchmarkCmd), Benchmark(frame_benchmarking_cli::BenchmarkCmd),
/// DB meta columns information // DB meta columns information
ChainInfo(sc_cli::ChainInfoCmd), ChainInfo(sc_cli::ChainInfoCmd),
} }

View file

@ -31,23 +31,23 @@ pub use pallet_balances::Call as BalancesCall;
use pallet_transaction_payment::CurrencyAdapter; use pallet_transaction_payment::CurrencyAdapter;
use pallet_contracts::{migration, DefaultContractAccessWeight}; use pallet_contracts::{migration, DefaultContractAccessWeight};
/// An index to a block /// An index to a block.
pub type BlockNumber = u32; pub type BlockNumber = u32;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain /// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature; pub type Signature = MultiSignature;
/// Some way of identifying an account on the chain. We intentionally make it equivalent /// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme /// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId; pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
/// Balance of an account /// Balance of an account.
pub type Balance = u64; pub type Balance = u64;
/// Index of a transaction in the chain, for a given account /// Index of a transaction in the chain, for a given account.
pub type Index = u32; pub type Index = u32;
/// A hash of some data used by the chain /// A hash of some data used by the chain.
pub type Hash = sp_core::H256; pub type Hash = sp_core::H256;
pub mod opaque { pub mod opaque {
@ -79,7 +79,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const MILLISECS_PER_BLOCK: u64 = 6000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
/// Measured in blocks /// Measured in blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60; pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24; pub const DAYS: BlockNumber = HOURS * 24;