Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep polynomial constant parameters during DKG #92

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
307fe19
add common::Polynomial; use Vec<Scalar> for private polynomial
xoloki Oct 8, 2024
8b3aa33
add commented out Polynomial::new; add Polynomial test
xoloki Oct 8, 2024
1d6c447
fix state machine tests by adding keep_constant field to DkgBegin; fi…
xoloki Oct 8, 2024
69c40d5
clippy fixes
xoloki Oct 8, 2024
7a53a8d
pass keep_constant from start_dkg_round down
xoloki Oct 8, 2024
93a4d35
add tests to show that keep_constant works on signers and on full sta…
xoloki Oct 8, 2024
995dd89
fix common::Polynomial eval and reenable test
xoloki Oct 8, 2024
4c85a3b
fix comment on commented out Polynomial::random
xoloki Oct 8, 2024
020d5e8
add Random trait and use it to reenable Polynomial::random
xoloki Oct 8, 2024
39c117f
polys have degree not size
xoloki Oct 8, 2024
0fa4043
use Polynomial::random in unit test
xoloki Oct 8, 2024
7ade470
remove unused import
xoloki Oct 8, 2024
6f81a1d
use common::Polynomial for private polys; add operators and helpers t…
xoloki Oct 9, 2024
2089718
clippy wants an is_empty if there's a len, and doesn't like needless …
xoloki Oct 9, 2024
2b6d213
use where clause for long trait bounds
xoloki Oct 9, 2024
50adba3
make polynomial mul completely generic so it can return a different v…
xoloki Oct 9, 2024
cf05e0d
add Mul impl for &Polynomial to avoid cloning a reference poly
xoloki Oct 9, 2024
85ae892
remove compute::private_poly since we can just use common::Polynomial
xoloki Oct 9, 2024
9658791
expand on TupleProof comments and change challenge var to c
xoloki Oct 10, 2024
64dd754
swap ordering of a and c in TupleProof to match normal Schnorr usage
xoloki Oct 10, 2024
06b1e89
return error if we're in DkgPublicDistribute during process_message loop
xoloki Oct 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wsts"
version = "9.2.0"
version = "10.0.0"
edition = "2021"
authors = ["Joey Yandle <[email protected]>"]
license = "Apache-2.0"
Expand Down
187 changes: 178 additions & 9 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::{
fmt::{Debug, Display, Formatter, Result as FmtResult},
ops::Add,
ops::{Add, AddAssign, Index, Mul, MulAssign},
};
use hashbrown::HashMap;
use num_traits::{One, Zero};
Expand All @@ -22,6 +22,122 @@ use crate::{
/// A merkle root is a 256 bit hash
pub type MerkleRoot = [u8; 32];

/// A trait that allows us to create random instances of implementors
pub trait Random {
/// Create a new instance with random data
fn fill<RNG: RngCore + CryptoRng>(rng: &mut RNG) -> Self;
}

impl Random for Point {
fn fill<RNG: RngCore + CryptoRng>(rng: &mut RNG) -> Self {
Point::from(Scalar::random(rng))
}
}

impl Random for Scalar {
fn fill<RNG: RngCore + CryptoRng>(rng: &mut RNG) -> Self {
Scalar::random(rng)
}
}

/// A Polynomial where the parameters are not necessarily the same type as the args
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct Polynomial<Param, Arg> {
djordon marked this conversation as resolved.
Show resolved Hide resolved
/// parameters for the polynomial
pub params: Vec<Param>,
_x: std::marker::PhantomData<Arg>,
}

impl<Param, Arg> Polynomial<Param, Arg>
where
Param: Clone + Zero + Random + Add + AddAssign<<Arg as Mul<Param>>::Output>,
Arg: Clone + One + Mul<Param> + MulAssign,
{
/// construct new random polynomial of the specified degree
pub fn random<RNG: RngCore + CryptoRng>(n: u32, rng: &mut RNG) -> Self {
let params = (0..n + 1).map(|_| Param::fill(rng)).collect::<Vec<Param>>();
Self {
params,
_x: std::marker::PhantomData,
}
}

/// construct new polynomial from passed params
pub fn new(params: Vec<Param>) -> Self {
Self {
params,
_x: std::marker::PhantomData,
}
}
/// evaluate the polynomial with the passed arg
pub fn eval(&self, x: Arg) -> Param {
let mut pow = Arg::one();
let mut ret = Param::zero();
for i in 0..self.params.len() {
ret += pow.clone() * self.params[i].clone();
pow *= x.clone();
}
ret
}

/// length of the params
pub fn len(&self) -> usize {
self.params.len()
}

/// is the length of the polynomial zero
pub fn is_empty(&self) -> bool {
self.params.is_empty()
}
}

impl<Param, Arg> Index<usize> for Polynomial<Param, Arg> {
type Output = Param;
fn index(&self, i: usize) -> &Param {
&self.params[i]
}
}

impl<Param, Arg, Operand, OpResult> Mul<Operand> for &Polynomial<Param, Arg>
where
Param: Clone
+ Zero
+ Random
+ Add
+ AddAssign<<Arg as Mul<Param>>::Output>
+ Mul<Operand, Output = OpResult>,
Arg: Clone + One + Mul<OpResult> + Mul<Param> + MulAssign,
Operand: Clone,
OpResult: Clone + Zero + Random + Add + AddAssign<<Arg as Mul<OpResult>>::Output>,
Vec<OpResult>: FromIterator<<Param as Mul<Operand>>::Output>,
{
type Output = Polynomial<OpResult, Arg>;
fn mul(self, x: Operand) -> Self::Output {
let params: Vec<OpResult> = self.params.iter().map(|p| p.clone() * x.clone()).collect();
Polynomial::new(params)
}
}

impl<Param, Arg, Operand, OpResult> Mul<Operand> for Polynomial<Param, Arg>
where
Param: Clone
+ Zero
+ Random
+ Add
+ AddAssign<<Arg as Mul<Param>>::Output>
+ Mul<Operand, Output = OpResult>,
djordon marked this conversation as resolved.
Show resolved Hide resolved
Arg: Clone + One + Mul<OpResult> + Mul<Param> + MulAssign,
Operand: Clone,
OpResult: Clone + Zero + Random + Add + AddAssign<<Arg as Mul<OpResult>>::Output>,
Vec<OpResult>: FromIterator<<Param as Mul<Operand>>::Output>,
{
type Output = Polynomial<OpResult, Arg>;
fn mul(self, x: Operand) -> Self::Output {
let params: Vec<OpResult> = self.params.iter().map(|p| p.clone() * x.clone()).collect();
djordon marked this conversation as resolved.
Show resolved Hide resolved
Polynomial::new(params)
}
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// A commitment to a polynonial, with a Schnorr proof of ownership bound to the ID
pub struct PolyCommitment {
Expand Down Expand Up @@ -161,19 +277,20 @@ impl Signature {

#[allow(non_snake_case)]
/// A Chaum-Pedersen proof that (G, A=a*G, B=b*G, K=(a*b)*G) is a DH tuple
/// It consists of two Schnorr proofs. The first shows knowledge of `a`, and the second is just the first multiplied by `b`
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct TupleProof {
/// R = r*G for a random scalar r
pub R: Point,
/// rB = r*B
/// rB = r*B = b*R
pub rB: Point,
/// z = r + a*s where s = H(G,A,B,K,R) as per Fiat-Shamir
/// z = r + c*a where c = H(G,A,B,K,R) as per Fiat-Shamir
pub z: Scalar,
}

impl TupleProof {
#[allow(non_snake_case)]
/// Construct a Chaum-Pedersen proof that (G, A, B, K) is a DH tuple
/// Construct a Chaum-Pedersen proof that (A, B, K) is a DH tuple
pub fn new<RNG: RngCore + CryptoRng>(
a: &Scalar,
A: &Point,
Expand All @@ -183,21 +300,21 @@ impl TupleProof {
) -> Self {
let r = Scalar::random(rng);
let R = r * G;
let s = Self::challenge(A, B, K, &R);
let c = Self::challenge(A, B, K, &R);

Self {
R,
rB: r * B,
z: r + a * s,
z: r + c * a,
}
}

#[allow(non_snake_case)]
/// Verify the proof using the transcript and public parameters
pub fn verify(&self, A: &Point, B: &Point, K: &Point) -> bool {
let s = Self::challenge(A, B, K, &self.R);
let c = Self::challenge(A, B, K, &self.R);

(self.z * G == self.R + s * A) && (self.z * B == self.rB + s * K)
(self.z * G == self.R + c * A) && (self.z * B == self.rB + c * K)
}

#[allow(non_snake_case)]
Expand Down Expand Up @@ -321,13 +438,65 @@ pub mod test_helpers {

#[cfg(test)]
pub mod test {
use num_traits::Zero;
use rand_core::OsRng;

use crate::{
common::TupleProof,
curve::{point::Point, scalar::Scalar},
compute,
curve::{
point::{Point, G},
scalar::Scalar,
},
};

#[test]
#[allow(non_snake_case)]
fn polynomial() {
let mut rng = OsRng;
let n = 16u32;

let poly = super::Polynomial::<Scalar, Scalar>::random(n - 1, &mut rng);
let x = Scalar::from(8);
let y = poly.eval(x);
let mut z = Scalar::zero();
let mut pow = Scalar::from(1);
for i in 0..poly.params.len() {
z += pow * poly.params[i];
pow *= x;
}
assert_eq!(y, z);

let public_params = poly.params.iter().map(|p| p * G).collect::<Vec<Point>>();
let public_poly: super::Polynomial<Point, Scalar> =
super::Polynomial::new(public_params.clone());
let a = poly.eval(x);
let b = public_poly.eval(x);
assert_eq!(a * G, b);

let mul_poly = poly * G;
let b = mul_poly.eval(x);
assert_eq!(a * G, b);

let b = compute::poly(&x, &public_params);
assert_eq!(a * G, b.unwrap());

let poly = super::Polynomial::random(n - 1, &mut rng);
let params = poly.params.clone();
let y = poly.eval(x);
let mut z = Point::zero();
let mut pow = Scalar::from(1);
for i in 0..poly.params.len() {
z += pow * poly.params[i];
pow *= x;
}
assert_eq!(y, z);

let a = poly.eval(x);
let b = compute::poly(&x, &params);
assert_eq!(a, b.unwrap());
}

#[test]
#[allow(non_snake_case)]
fn tuple_proof() {
Expand Down
27 changes: 27 additions & 0 deletions src/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,30 @@ pub fn merkle_root(data: &[u8]) -> [u8; 32] {

hasher.finalize().into()
}

#[cfg(test)]
pub mod test {
use rand_core::OsRng;

use crate::{
common::Polynomial,
compute,
curve::{point::G, scalar::Scalar},
};

#[test]
#[allow(non_snake_case)]
fn poly() {
let mut rng = OsRng;
let n = 16u32;

let private_poly = Polynomial::<Scalar, Scalar>::random(n - 1, &mut rng);
let public_poly = &private_poly * G;

let x = Scalar::from(8);
let a = private_poly.eval(x);
let b = compute::poly(&x, &public_poly.params);

assert_eq!(a * G, b.unwrap());
}
}
9 changes: 8 additions & 1 deletion src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,16 @@ impl Signable for Message {
pub struct DkgBegin {
/// DKG round ID
pub dkg_id: u64,
/// Keep the constant factor so DKG will produce the same key
pub keep_constant: bool,
}

impl Signable for DkgBegin {
fn hash(&self, hasher: &mut Sha256) {
let keep_constant = if self.keep_constant { [1u8] } else { [0u8] };
hasher.update("DKG_BEGIN".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(keep_constant);
}
}

Expand Down Expand Up @@ -629,7 +633,10 @@ mod test {
#[test]
fn dkg_begin_verify_msg() {
let test_config = TestConfig::default();
let dkg_begin = DkgBegin { dkg_id: 0 };
let dkg_begin = DkgBegin {
dkg_id: 0,
keep_constant: false,
};
let dkg_private_begin = DkgPrivateBegin {
dkg_id: 0,
key_ids: Default::default(),
Expand Down
Loading
Loading