Skip to content

Commit

Permalink
Add ProductionParams and docs for public exports
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Aug 27, 2023
1 parent 3d2de8f commit dbcf5eb
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 172 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Threshold signing library based on CGGMP'21 scheme.

This library is based on the scheme described in "UC Non-Interactive, Proactive, Threshold ECDSA with Identifiable Aborts" by R. Canetti, R. Gennaro, S. Goldfeder, N. Makriyannis, and U. Peled, DOI:10.1145/3372297.3423367 (preprint is available at https://eprint.iacr.org/2021/060, and it has been revised compared to the published version).
This library is based on the scheme described in "UC Non-Interactive, Proactive, Threshold ECDSA with Identifiable Aborts" by R. Canetti, R. Gennaro, S. Goldfeder, N. Makriyannis, and U. Peled, DOI:10.1145/3372297.3423367 (preprint is available at <https://eprint.iacr.org/2021/060>, and it has been revised compared to the published version).
6 changes: 3 additions & 3 deletions synedrion-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rand_core::OsRng;
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
use wasm_bindgen_derive::TryFromJsValue;

use synedrion::TestSchemeParams;
use synedrion::TestParams;

extern crate alloc;

Expand Down Expand Up @@ -47,7 +47,7 @@ impl SigningKey {
#[derive(TryFromJsValue)]
#[wasm_bindgen]
#[derive(Clone)]
pub struct KeyShare(synedrion::KeyShare<TestSchemeParams>);
pub struct KeyShare(synedrion::KeyShare<TestParams>);

#[wasm_bindgen]
impl KeyShare {
Expand Down Expand Up @@ -76,7 +76,7 @@ impl KeyShare {

let backend_sk = typed_sk.map(|sk| sk.0);

let shares = synedrion::KeyShare::<TestSchemeParams>::new_centralized(
let shares = synedrion::KeyShare::<TestParams>::new_centralized(
&mut OsRng,
num_parties,
backend_sk.as_ref(),
Expand Down
7 changes: 3 additions & 4 deletions synedrion-wasm/tests-js/src/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import {
makeKeyShares,
KeyShare,
} from "synedrion";

describe("makeKeyShares", () => {
describe("KeyShare.newCentralized()", () => {
it("creates shares", () => {
const shares = makeKeyShares(2, undefined);
const shares = KeyShare.newCentralized(2, undefined);
expect(shares.length).toEqual(2);
expect(shares[0]).toEqual(expect.any(KeyShare));
expect(shares[1]).toEqual(expect.any(KeyShare));
Expand All @@ -14,7 +13,7 @@ describe("makeKeyShares", () => {

describe("KeyShare", () => {
it("serializes", () => {
const shares = makeKeyShares(2, undefined);
const shares = KeyShare.newCentralized(2, undefined);
expect(shares[0].toBytes()).toEqual(expect.any(Uint8Array));
});
});
2 changes: 1 addition & 1 deletion synedrion/src/cggmp21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod params;
mod protocols;
pub(crate) mod sigma;

pub use params::{SchemeParams, TestSchemeParams};
pub use params::{ProductionParams, SchemeParams, TestParams};
pub(crate) use protocols::{
auxiliary, interactive_signing, keygen_and_aux, FinalizeError, FinalizeSuccess, FirstRound,
InitError, ReceiveError, Round, ToSendTyped,
Expand Down
52 changes: 38 additions & 14 deletions synedrion/src/cggmp21/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,52 @@ use crate::curve::ORDER;
use crate::paillier::{PaillierParams, PaillierTest};
use crate::uint::upcast_uint;

/// Signing scheme parameters.
// TODO (#27): this trait can include curve scalar/point types as well,
// but for now they are hardcoded to `k256`.
pub trait SchemeParams: Clone + Send {
const SECURITY_PARAMETER: usize; // `\kappa`
// TODO: better names for the bounds
const L_BOUND: usize; // `\ell`
const LP_BOUND: usize; // `\ell^\prime`
const EPS_BOUND: usize; // `\eps`
type Paillier: PaillierParams;
const CURVE_ORDER: <Self::Paillier as PaillierParams>::DoubleUint;
}

#[derive(Clone)]
pub struct TestSchemeParams;

// TODO: additional requirements from range proofs etc:
// - $П_{enc}$, safe two's complement representation of $\alpha$ requires
// `L_BOUND + EPS_BOUND + 1 < DoubleUint::BITS - 1`
// - $П_{enc}$, safe two's complement representation of $z_1$ requires
// `L_BOUND + max(EPS_BOUND, log2(q)) + 1 < DoubleUint::BITS - 1`
// (where `q` is the curve order)
impl SchemeParams for TestSchemeParams {
// - Range checks will fail with the probability $q / 2^\eps$, so $\eps$ should be large enough.
pub trait SchemeParams: Clone + Send {
/// The order of the curve.
const CURVE_ORDER: <Self::Paillier as PaillierParams>::DoubleUint; // $q$
/// The sheme's statistical security parameter.
const SECURITY_PARAMETER: usize; // $\kappa$
// TODO: better names for the bounds?
// See Table 2 in the paper for the respective values of these parameters.
/// The bound for secret values.
const L_BOUND: usize; // $\ell$, paper sets it to $\log2(q)$
/// The error bound for secret masks.
const LP_BOUND: usize; // $\ell^\prime$, in paper $= 5 \ell$
/// The error bound for range checks.
const EPS_BOUND: usize; // $\eps$, in paper $= 2 \ell$
/// The parameters of the Paillier encryption.
type Paillier: PaillierParams;
}

/// Scheme parameters **for testing purposes only**.
/// Security is weakened to allow for faster execution.
#[derive(Debug, Copy, Clone)]
pub struct TestParams;

impl SchemeParams for TestParams {
const SECURITY_PARAMETER: usize = 10;
const L_BOUND: usize = 256;
const LP_BOUND: usize = 256;
const EPS_BOUND: usize = 320;
type Paillier = PaillierTest;
const CURVE_ORDER: <Self::Paillier as PaillierParams>::DoubleUint = upcast_uint(ORDER);
}

/// Production strength parameters.
#[derive(Debug, Copy, Clone)]
pub struct ProductionParams;

impl SchemeParams for ProductionParams {
const SECURITY_PARAMETER: usize = 10;
const L_BOUND: usize = 256;
const LP_BOUND: usize = 256;
Expand Down
8 changes: 4 additions & 4 deletions synedrion/src/cggmp21/protocols/auxiliary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ mod tests {
FirstRound,
};
use super::Round1;
use crate::cggmp21::{PartyIdx, TestSchemeParams};
use crate::cggmp21::{PartyIdx, TestParams};
use crate::curve::Scalar;

#[test]
Expand All @@ -513,23 +513,23 @@ mod tests {
OsRng.fill_bytes(&mut shared_randomness);

let r1 = vec![
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
PartyIdx::from_usize(0),
(),
)
.unwrap(),
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
PartyIdx::from_usize(1),
(),
)
.unwrap(),
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
Expand Down
71 changes: 62 additions & 9 deletions synedrion/src/cggmp21/protocols/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ use crate::paillier::{PaillierParams, PublicKeyPaillier, SecretKeyPaillier};
use crate::tools::hashing::{Chain, Hashable};
use crate::uint::Zero;

/// A typed integer denoting the index of a party in the group.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PartyIdx(u32);

impl PartyIdx {
pub fn as_usize(self) -> usize {
pub(crate) fn as_usize(self) -> usize {
self.0.try_into().unwrap()
}

/// Wraps an integers into the party index.
pub fn from_usize(val: usize) -> Self {
Self(val.try_into().unwrap())
}
Expand All @@ -30,14 +32,19 @@ impl Hashable for PartyIdx {
}

/// The result of the Keygen protocol.
// TODO: Debug can be derived automatically here if `secret_share` is wrapped in its own struct,
// or in a `SecretBox`-type wrapper.
#[derive(Clone)]
pub struct KeyShareSeed {
/// Secret key share of this node.
pub secret_share: Scalar, // `x_i`
pub(crate) secret_share: Scalar, // `x_i`
/// Public key shares of all nodes (including this one).
pub public_shares: Box<[Point]>, // `X_j`
pub(crate) public_shares: Box<[Point]>, // `X_j`
}

/// The full key share with auxiliary parameters.
// TODO: Debug can be derived automatically here if `secret_share` is wrapped in its own struct,
// or in a `SecretBox`-type wrapper.
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "SecretAuxInfo<P>: Serialize,
PublicAuxInfo<P>: Serialize"))]
Expand All @@ -51,6 +58,8 @@ pub struct KeyShare<P: SchemeParams> {
pub(crate) public_aux: Box<[PublicAuxInfo<P>]>,
}

// TODO: Debug can be derived automatically here if `el_gamal_sk` is wrapped in its own struct,
// or in a `SecretBox`-type wrapper.
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "SecretKeyPaillier<P::Paillier>: Serialize"))]
#[serde(bound(deserialize = "SecretKeyPaillier<P::Paillier>: for <'x> Deserialize<'x>"))]
Expand All @@ -59,7 +68,7 @@ pub(crate) struct SecretAuxInfo<P: SchemeParams> {
pub(crate) el_gamal_sk: Scalar, // `y_i`
}

#[derive(Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "PublicKeyPaillier<P::Paillier>: Serialize"))]
#[serde(bound(deserialize = "PublicKeyPaillier<P::Paillier>: for <'x> Deserialize<'x>"))]
pub(crate) struct PublicAuxInfo<P: SchemeParams> {
Expand All @@ -73,7 +82,7 @@ pub(crate) struct PublicAuxInfo<P: SchemeParams> {
}

/// The result of the Auxiliary Info & Key Refresh protocol - the update to the key share.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct KeyShareChange<P: SchemeParams> {
pub(crate) index: PartyIdx,
/// The value to be added to the secret share.
Expand All @@ -85,7 +94,7 @@ pub struct KeyShareChange<P: SchemeParams> {
}

/// The result of the Presigning protocol.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct PresigningData {
pub(crate) nonce: Point, // `R`
/// An additive share of the ephemeral scalar `k`.
Expand All @@ -95,6 +104,8 @@ pub struct PresigningData {
}

impl<P: SchemeParams> KeyShare<P> {
/// Creates a key share out of the seed (obtained from the KeyGen protocol)
/// and the share change (obtained from the KeyRefresh+Auxiliary protocol).
pub fn new(seed: KeyShareSeed, change: KeyShareChange<P>) -> Self {
// TODO: check that party_idx is the same for both, and the number of parties is the same
let secret_share = seed.secret_share + change.secret_share_change;
Expand Down Expand Up @@ -147,6 +158,8 @@ impl<P: SchemeParams> KeyShare<P> {
.collect()
}

/// Return the updated key share using the share change
/// obtained from the KeyRefresh+Auxiliary protocol).
pub fn update(self, change: KeyShareChange<P>) -> Self {
// TODO: check that party_idx is the same for both, and the number of parties is the same
let secret_share = self.secret_share + change.secret_share_change;
Expand All @@ -169,26 +182,66 @@ impl<P: SchemeParams> KeyShare<P> {
self.public_shares.iter().sum()
}

/// Return the verifying key to which this set of shares corresponds.
pub fn verifying_key(&self) -> VerifyingKey {
// TODO: need to ensure on creation of the share that the verifying key actually exists
// (that is, the sum of public keys does not evaluate to the infinity point)
self.verifying_key_as_point().to_verifying_key().unwrap()
}

/// Returns the number of parties in this set of shares.
pub fn num_parties(&self) -> usize {
// TODO: technically it is `num_shares`, but for now we are equating the two,
// since we assume that one party has one share.
self.public_shares.len()
}

/// Returns the index of this share's party.
pub fn party_index(&self) -> PartyIdx {
// TODO: technically it is the share index, but for now we are equating the two,
// since we assume that one party has one share.
self.index
}
}

impl<P: SchemeParams> core::fmt::Debug for KeyShare<P> {
// A custom Debug impl that skips the secret value
impl core::fmt::Debug for KeyShareSeed {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
"KeySeed {{ secret_share: <...>, public_shares: {:?} }}",
self.public_shares,
)
}
}

// A custom Debug impl that skips the secret value
impl<P: SchemeParams> core::fmt::Debug for SecretAuxInfo<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(f, "SecretAuxInfo {{ <...> }}",)
}
}

// A custom Debug impl that skips the secret values
impl<P: SchemeParams + core::fmt::Debug> core::fmt::Debug for KeyShare<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
concat![
"KeyShare {{",
"index: {:?}, ",
"secret_share: <...>, ",
"public_shares: {:?}, ",
"secret_aux: {:?}, ",
"public_aux: {:?} ",
"}}"
],
self.index, self.public_shares, self.secret_aux, self.public_aux
)
}
}

impl<P: SchemeParams> core::fmt::Display for KeyShare<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
f,
Expand Down Expand Up @@ -230,12 +283,12 @@ mod tests {
use rand_core::OsRng;

use super::KeyShare;
use crate::TestSchemeParams;
use crate::TestParams;

#[test]
fn key_share_centralized() {
let sk = SigningKey::random(&mut OsRng);
let shares = KeyShare::<TestSchemeParams>::new_centralized(&mut OsRng, 3, Some(&sk));
let shares = KeyShare::<TestParams>::new_centralized(&mut OsRng, 3, Some(&sk));
assert_eq!(&shares[0].verifying_key(), sk.verifying_key());
}
}
8 changes: 4 additions & 4 deletions synedrion/src/cggmp21/protocols/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,31 +304,31 @@ mod tests {
FirstRound,
};
use super::Round1;
use crate::cggmp21::{PartyIdx, TestSchemeParams};
use crate::cggmp21::{PartyIdx, TestParams};

#[test]
fn execute_keygen() {
let mut shared_randomness = [0u8; 32];
OsRng.fill_bytes(&mut shared_randomness);

let r1 = vec![
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
PartyIdx::from_usize(0),
(),
)
.unwrap(),
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
PartyIdx::from_usize(1),
(),
)
.unwrap(),
Round1::<TestSchemeParams>::new(
Round1::<TestParams>::new(
&mut OsRng,
&shared_randomness,
3,
Expand Down
Loading

0 comments on commit dbcf5eb

Please sign in to comment.