mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-10 21:19:24 +00:00
Working multisig TXs
This commit is contained in:
@@ -4,7 +4,7 @@ use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use group::Group;
|
||||
|
||||
use crate::{Curve, FrostError, sign};
|
||||
use crate::{Curve, FrostError, MultisigView};
|
||||
|
||||
/// Algorithm to use FROST with
|
||||
pub trait Algorithm<C: Curve>: Clone {
|
||||
@@ -17,14 +17,14 @@ pub trait Algorithm<C: Curve>: Clone {
|
||||
/// Generate an addendum to FROST"s preprocessing stage
|
||||
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
params: &sign::ParamsView<C>,
|
||||
params: &MultisigView<C>,
|
||||
nonces: &[C::F; 2],
|
||||
) -> Vec<u8>;
|
||||
|
||||
/// Proccess the addendum for the specified participant. Guaranteed to be ordered
|
||||
fn process_addendum(
|
||||
&mut self,
|
||||
params: &sign::ParamsView<C>,
|
||||
params: &MultisigView<C>,
|
||||
l: usize,
|
||||
commitments: &[C::G; 2],
|
||||
serialized: &[u8],
|
||||
@@ -39,7 +39,7 @@ pub trait Algorithm<C: Curve>: Clone {
|
||||
/// The nonce will already have been processed into the combined form d + (e * p)
|
||||
fn sign_share(
|
||||
&mut self,
|
||||
params: &sign::ParamsView<C>,
|
||||
params: &MultisigView<C>,
|
||||
nonce_sum: C::G,
|
||||
b: C::F,
|
||||
nonce: C::F,
|
||||
@@ -98,7 +98,7 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
||||
|
||||
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
||||
_: &mut R,
|
||||
_: &sign::ParamsView<C>,
|
||||
_: &MultisigView<C>,
|
||||
_: &[C::F; 2],
|
||||
) -> Vec<u8> {
|
||||
vec![]
|
||||
@@ -106,7 +106,7 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
||||
|
||||
fn process_addendum(
|
||||
&mut self,
|
||||
_: &sign::ParamsView<C>,
|
||||
_: &MultisigView<C>,
|
||||
_: usize,
|
||||
_: &[C::G; 2],
|
||||
_: &[u8],
|
||||
@@ -120,7 +120,7 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
||||
|
||||
fn sign_share(
|
||||
&mut self,
|
||||
params: &sign::ParamsView<C>,
|
||||
params: &MultisigView<C>,
|
||||
nonce_sum: C::G,
|
||||
_: C::F,
|
||||
nonce: C::F,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::{ops::Mul, fmt::Debug};
|
||||
|
||||
use ff::PrimeField;
|
||||
use ff::{Field, PrimeField};
|
||||
use group::{Group, GroupOps, ScalarMul};
|
||||
|
||||
use thiserror::Error;
|
||||
@@ -8,6 +8,7 @@ use thiserror::Error;
|
||||
pub mod key_gen;
|
||||
pub mod algorithm;
|
||||
pub mod sign;
|
||||
use sign::lagrange;
|
||||
|
||||
/// Set of errors for curve-related operations, namely encoding and decoding
|
||||
#[derive(Error, Debug)]
|
||||
@@ -190,6 +191,33 @@ pub enum FrostError {
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
// View of keys passable to algorithm implementations
|
||||
#[derive(Clone)]
|
||||
pub struct MultisigView<C: Curve> {
|
||||
group_key: C::G,
|
||||
included: Vec<usize>,
|
||||
secret_share: C::F,
|
||||
verification_shares: Vec<C::G>,
|
||||
}
|
||||
|
||||
impl<C: Curve> MultisigView<C> {
|
||||
pub fn group_key(&self) -> C::G {
|
||||
self.group_key
|
||||
}
|
||||
|
||||
pub fn included(&self) -> Vec<usize> {
|
||||
self.included.clone()
|
||||
}
|
||||
|
||||
pub fn secret_share(&self) -> C::F {
|
||||
self.secret_share
|
||||
}
|
||||
|
||||
pub fn verification_share(&self, l: usize) -> C::G {
|
||||
self.verification_shares[l]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct MultisigKeys<C: Curve> {
|
||||
/// Multisig Parameters
|
||||
@@ -229,6 +257,30 @@ impl<C: Curve> MultisigKeys<C> {
|
||||
self.verification_shares.clone()
|
||||
}
|
||||
|
||||
pub fn view(&self, included: &[usize]) -> Result<MultisigView<C>, FrostError> {
|
||||
if (included.len() < self.params.t) || (self.params.n < included.len()) {
|
||||
Err(FrostError::InvalidSigningSet("invalid amount of participants included".to_string()))?;
|
||||
}
|
||||
|
||||
let secret_share = self.secret_share * lagrange::<C::F>(self.params.i, &included);
|
||||
let (offset, offset_share) = if self.offset.is_some() {
|
||||
let offset = self.offset.unwrap();
|
||||
(offset, offset * C::F::from(included.len().try_into().unwrap()).invert().unwrap())
|
||||
} else {
|
||||
(C::F::zero(), C::F::zero())
|
||||
};
|
||||
|
||||
Ok(MultisigView {
|
||||
group_key: self.group_key + (C::generator_table() * offset),
|
||||
secret_share: secret_share + offset_share,
|
||||
verification_shares: self.verification_shares.clone().iter().enumerate().map(
|
||||
|(l, share)| (*share * lagrange::<C::F>(l, &included)) +
|
||||
(C::generator_table() * offset_share)
|
||||
).collect(),
|
||||
included: included.to_vec(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn serialized_len(n: usize) -> usize {
|
||||
1 + usize::from(C::id_len()) + (3 * 8) + C::F_len() + C::G_len() + (n * C::G_len())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::{convert::{TryFrom, TryInto}, cmp::min, fmt};
|
||||
use core::{convert::TryFrom, cmp::min, fmt};
|
||||
use std::rc::Rc;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
@@ -6,7 +6,7 @@ use rand_core::{RngCore, CryptoRng};
|
||||
use ff::{Field, PrimeField};
|
||||
use group::Group;
|
||||
|
||||
use crate::{Curve, MultisigParams, MultisigKeys, FrostError, algorithm::Algorithm};
|
||||
use crate::{Curve, FrostError, MultisigParams, MultisigKeys, MultisigView, algorithm::Algorithm};
|
||||
|
||||
/// Calculate the lagrange coefficient
|
||||
pub fn lagrange<F: PrimeField>(
|
||||
@@ -30,39 +30,12 @@ pub fn lagrange<F: PrimeField>(
|
||||
num * denom.invert().unwrap()
|
||||
}
|
||||
|
||||
// View of params passable to algorithm implementations
|
||||
#[derive(Clone)]
|
||||
pub struct ParamsView<C: Curve> {
|
||||
group_key: C::G,
|
||||
included: Vec<usize>,
|
||||
secret_share: C::F,
|
||||
verification_shares: Vec<C::G>,
|
||||
}
|
||||
|
||||
impl<C: Curve> ParamsView<C> {
|
||||
pub fn group_key(&self) -> C::G {
|
||||
self.group_key
|
||||
}
|
||||
|
||||
pub fn included(&self) -> Vec<usize> {
|
||||
self.included.clone()
|
||||
}
|
||||
|
||||
pub fn secret_share(&self) -> C::F {
|
||||
self.secret_share
|
||||
}
|
||||
|
||||
pub fn verification_share(&self, l: usize) -> C::G {
|
||||
self.verification_shares[l]
|
||||
}
|
||||
}
|
||||
|
||||
/// Pairing of an Algorithm with a MultisigKeys instance and this specific signing set
|
||||
#[derive(Clone)]
|
||||
pub struct Params<C: Curve, A: Algorithm<C>> {
|
||||
algorithm: A,
|
||||
keys: Rc<MultisigKeys<C>>,
|
||||
view: ParamsView<C>,
|
||||
view: MultisigView<C>,
|
||||
}
|
||||
|
||||
// Currently public to enable more complex operations as desired, yet solely used in testing
|
||||
@@ -75,7 +48,7 @@ impl<C: Curve, A: Algorithm<C>> Params<C, A> {
|
||||
let mut included = included.to_vec();
|
||||
(&mut included).sort_unstable();
|
||||
|
||||
// included < threshold
|
||||
// Included < threshold
|
||||
if included.len() < keys.params.t {
|
||||
Err(FrostError::InvalidSigningSet("not enough signers".to_string()))?;
|
||||
}
|
||||
@@ -98,37 +71,15 @@ impl<C: Curve, A: Algorithm<C>> Params<C, A> {
|
||||
Err(FrostError::InvalidSigningSet("signing despite not being included".to_string()))?;
|
||||
}
|
||||
|
||||
let secret_share = keys.secret_share * lagrange::<C::F>(keys.params.i, &included);
|
||||
let (offset, offset_share) = if keys.offset.is_some() {
|
||||
let offset = keys.offset.unwrap();
|
||||
(offset, offset * C::F::from(included.len().try_into().unwrap()).invert().unwrap())
|
||||
} else {
|
||||
(C::F::zero(), C::F::zero())
|
||||
};
|
||||
|
||||
Ok(
|
||||
Params {
|
||||
algorithm,
|
||||
// Out of order arguments to prevent additional cloning
|
||||
view: ParamsView {
|
||||
group_key: keys.group_key + (C::generator_table() * offset),
|
||||
secret_share: secret_share + offset_share,
|
||||
verification_shares: keys.verification_shares.clone().iter().enumerate().map(
|
||||
|(l, share)| (*share * lagrange::<C::F>(l, &included)) +
|
||||
(C::generator_table() * offset_share)
|
||||
).collect(),
|
||||
included: included,
|
||||
},
|
||||
keys
|
||||
}
|
||||
)
|
||||
// Out of order arguments to prevent additional cloning
|
||||
Ok(Params { algorithm, view: keys.view(&included).unwrap(), keys })
|
||||
}
|
||||
|
||||
pub fn multisig_params(&self) -> MultisigParams {
|
||||
self.keys.params
|
||||
}
|
||||
|
||||
pub fn view(&self) -> ParamsView<C> {
|
||||
pub fn view(&self) -> MultisigView<C> {
|
||||
self.view.clone()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user