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

Signed improvements #166

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions synedrion/src/cggmp21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! refers to the version of the paper published at <https://eprint.iacr.org/2021/060.pdf>

mod aux_gen;
mod conversion;
mod entities;
mod interactive_signing;
mod key_init;
Expand Down
163 changes: 163 additions & 0 deletions synedrion/src/cggmp21/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use crypto_bigint::{Encoding, Zero};

use super::params::SchemeParams;
use crate::{
curve::{Scalar, ORDER},
paillier::PaillierParams,
tools::Secret,
uint::{PublicSigned, SecretSigned, SecretUnsigned},
};

fn uint_from_scalar<P: SchemeParams>(value: &Scalar) -> <P::Paillier as PaillierParams>::Uint {
let scalar_bytes = value.to_be_bytes();
let mut repr = <P::Paillier as PaillierParams>::Uint::zero().to_be_bytes();

let uint_len = repr.as_ref().len();
let scalar_len = scalar_bytes.len();

repr.as_mut()
.get_mut(uint_len - scalar_len..)
.expect("PaillierParams::Uint is expected to be bigger than a Scalar")
.copy_from_slice(&scalar_bytes);
<P::Paillier as PaillierParams>::Uint::from_be_bytes(repr)
}

/// Converts a [`Scalar`] to a [`PublicSigned`].
///
/// Assumes using a curve whose order is at most the width of `Uint` minus 1 bit.
pub(crate) fn public_signed_from_scalar<P: SchemeParams>(
fjarri marked this conversation as resolved.
Show resolved Hide resolved
value: &Scalar,
) -> PublicSigned<<P::Paillier as PaillierParams>::Uint> {
PublicSigned::new_positive(uint_from_scalar::<P>(value), ORDER.bits_vartime() as u32).expect(concat![
"a curve scalar value is smaller than the half of `PaillierParams::Uint` range, ",
"so it is still positive when treated as a 2-complement signed value"
])
}

/// Converts an integer to the associated curve scalar type.
pub(crate) fn scalar_from_uint<P: SchemeParams>(value: &<P::Paillier as PaillierParams>::Uint) -> Scalar {
let r = *value % P::CURVE_ORDER;

let repr = r.to_be_bytes();
let uint_len = repr.as_ref().len();
let scalar_len = Scalar::repr_len();

// Can unwrap here since the value is within the Scalar range
Scalar::try_from_be_bytes(
repr.as_ref()
.get(uint_len - scalar_len..)
.expect("Uint is assumed to be bigger than Scalar"),
)
.expect("the value was reduced modulo curve order, so it's a valid curve scalar")
}

/// Converts a `PublicSigned`-wrapped integer to the associated curve scalar type.
pub(crate) fn scalar_from_signed<P: SchemeParams>(
value: &PublicSigned<<P::Paillier as PaillierParams>::Uint>,
) -> Scalar {
let abs_value = scalar_from_uint::<P>(&value.abs());
if value.is_negative() {
-abs_value
} else {
abs_value
}
}

/// Converts a wide integer to the associated curve scalar type.
pub(crate) fn scalar_from_wide_uint<P: SchemeParams>(value: &<P::Paillier as PaillierParams>::WideUint) -> Scalar {
let r = *value % P::CURVE_ORDER_WIDE;

let repr = r.to_be_bytes();
let uint_len = repr.as_ref().len();
let scalar_len = Scalar::repr_len();

// Can unwrap here since the value is within the Scalar range
Scalar::try_from_be_bytes(
repr.as_ref()
.get(uint_len - scalar_len..)
.expect("WideUint is assumed to be bigger than Scalar"),
)
.expect("the value was reduced modulo curve order, so it's a valid curve scalar")
}

/// Converts a `PublicSigned`-wrapped wide integer to the associated curve scalar type.
pub(crate) fn scalar_from_wide_signed<P: SchemeParams>(
value: &PublicSigned<<P::Paillier as PaillierParams>::WideUint>,
) -> Scalar {
let abs_value = scalar_from_wide_uint::<P>(&value.abs());
if value.is_negative() {
-abs_value
} else {
abs_value
}
}

/// Converts a secret-wrapped uint to a secret-wrapped [`Scalar`], reducing the value modulo curve order.
pub(crate) fn secret_scalar_from_uint<P: SchemeParams>(
fjarri marked this conversation as resolved.
Show resolved Hide resolved
value: &Secret<<P::Paillier as PaillierParams>::Uint>,
) -> Secret<Scalar> {
let r = value % &P::CURVE_ORDER;

let repr = Secret::init_with(|| r.expose_secret().to_be_bytes());
let uint_len = repr.expose_secret().as_ref().len();
let scalar_len = Scalar::repr_len();

// Can unwrap here since the value is within the Scalar range
Secret::init_with(|| {
Scalar::try_from_be_bytes(
repr.expose_secret()
.as_ref()
.get(uint_len - scalar_len..)
.expect("Uint is assumed to be bigger than Scalar"),
)
.expect("the value was reduced modulo `CURVE_ORDER`, so it's a valid curve scalar")
})
}

fn secret_uint_from_scalar<P: SchemeParams>(value: &Secret<Scalar>) -> Secret<<P::Paillier as PaillierParams>::Uint> {
let scalar_bytes = Secret::init_with(|| value.expose_secret().to_be_bytes());
let mut repr = Secret::init_with(|| <P::Paillier as PaillierParams>::Uint::zero().to_be_bytes());

let uint_len = repr.expose_secret().as_ref().len();
let scalar_len = scalar_bytes.expose_secret().len();

debug_assert!(uint_len >= scalar_len);
repr.expose_secret_mut()
.as_mut()
.get_mut(uint_len - scalar_len..)
.expect("<P::Paillier as PaillierParams>::Uint is assumed to be configured to be bigger than Scalar")
.copy_from_slice(scalar_bytes.expose_secret());
Secret::init_with(|| <P::Paillier as PaillierParams>::Uint::from_be_bytes(*repr.expose_secret()))
}

/// Converts a secret-wrapped [`Scalar`] to a [`SecretUnsigned`].
///
/// Assumes using a curve whose order fits in a [`PaillierParams::Uint`].
pub(crate) fn secret_unsigned_from_scalar<P: SchemeParams>(
fjarri marked this conversation as resolved.
Show resolved Hide resolved
value: &Secret<Scalar>,
) -> SecretUnsigned<<P::Paillier as PaillierParams>::Uint> {
SecretUnsigned::new(secret_uint_from_scalar::<P>(value), ORDER.bits_vartime() as u32).expect(concat![
"a curve scalar value is smaller than the curve order, ",
"and the curve order fits in `PaillierParams::Uint`"
])
}

/// Converts a secret-wrapped [`Scalar`] to a [`SecretSigned`].
///
/// Assumes using a curve whose order is at most the width of `Uint` minus 1 bit.
pub(crate) fn secret_signed_from_scalar<P: SchemeParams>(
fjarri marked this conversation as resolved.
Show resolved Hide resolved
value: &Secret<Scalar>,
) -> SecretSigned<<P::Paillier as PaillierParams>::Uint> {
SecretSigned::new_positive(secret_uint_from_scalar::<P>(value), ORDER.bits_vartime() as u32).expect(concat![
"a curve scalar value is smaller than the curve order, ",
"and the curve order fits in `PaillierParams::Uint`"
])
}

/// Converts a [`SecretSigned`] to a secret-wrapped [`Scalar`].
pub(crate) fn secret_scalar_from_signed<P: SchemeParams>(
fjarri marked this conversation as resolved.
Show resolved Hide resolved
value: &SecretSigned<<P::Paillier as PaillierParams>::Uint>,
) -> Secret<Scalar> {
let abs_value = secret_scalar_from_uint::<P>(&value.abs_value());
Secret::<Scalar>::conditional_select(&abs_value, &-&abs_value, value.is_negative())
}
6 changes: 3 additions & 3 deletions synedrion/src/cggmp21/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
SecretKeyPaillier, SecretKeyPaillierWire,
},
tools::Secret,
uint::Signed,
uint::SecretSigned,
};

/// The result of the KeyInit protocol.
Expand Down Expand Up @@ -103,7 +103,7 @@ pub(crate) struct PresigningData<P: SchemeParams, I> {

// Values generated during presigning,
// kept in case we need to generate a proof of correctness.
pub(crate) product_share_nonreduced: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
pub(crate) product_share_nonreduced: SecretSigned<<P::Paillier as PaillierParams>::Uint>,

// $K_i$.
pub(crate) cap_k: Ciphertext<P::Paillier>,
Expand All @@ -114,7 +114,7 @@ pub(crate) struct PresigningData<P: SchemeParams, I> {

#[derive(Debug, Clone)]
pub(crate) struct PresigningValues<P: SchemeParams> {
pub(crate) hat_beta: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
pub(crate) hat_beta: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
pub(crate) hat_r: Randomizer<P::Paillier>,
pub(crate) hat_s: Randomizer<P::Paillier>,
pub(crate) cap_k: Ciphertext<P::Paillier>,
Expand Down
79 changes: 36 additions & 43 deletions synedrion/src/cggmp21/interactive_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};

use super::{
entities::{AuxInfo, AuxInfoPrecomputed, KeyShare, PresigningData, PresigningValues, PublicAuxInfoPrecomputed},
params::{
bounded_from_scalar, secret_bounded_from_scalar, secret_scalar_from_signed, secret_signed_from_scalar,
secret_uint_from_scalar, signed_from_scalar, SchemeParams,
conversion::{
public_signed_from_scalar, secret_scalar_from_signed, secret_signed_from_scalar, secret_unsigned_from_scalar,
},
entities::{AuxInfo, AuxInfoPrecomputed, KeyShare, PresigningData, PresigningValues, PublicAuxInfoPrecomputed},
params::SchemeParams,
sigma::{AffGProof, DecProof, EncProof, LogStarProof, MulProof, MulStarProof},
};
use crate::{
Expand All @@ -32,7 +32,7 @@ use crate::{
hashing::{Chain, FofHasher, HashOutput},
DowncastMap, Secret, Without,
},
uint::Signed,
uint::SecretSigned,
};

/// A protocol for creating all the data necessary for signing
Expand Down Expand Up @@ -162,10 +162,10 @@ impl<P: SchemeParams, I: PartyId> EntryPoint<I> for InteractiveSigning<P, I> {
let pk = aux_info.secret_aux.paillier_sk.public_key();

let nu = Randomizer::<P::Paillier>::random(rng, pk);
let cap_g = Ciphertext::new_with_randomizer(pk, &secret_uint_from_scalar::<P>(&gamma), &nu);
let cap_g = Ciphertext::new_with_randomizer(pk, &secret_unsigned_from_scalar::<P>(&gamma), &nu);

let rho = Randomizer::<P::Paillier>::random(rng, pk);
let cap_k = Ciphertext::new_with_randomizer(pk, &secret_uint_from_scalar::<P>(&k), &rho);
let cap_k = Ciphertext::new_with_randomizer(pk, &secret_unsigned_from_scalar::<P>(&k), &rho);

Ok(BoxedRound::new_dynamic(Round1 {
context: Context {
Expand Down Expand Up @@ -421,8 +421,8 @@ struct Round2Message<P: SchemeParams> {

#[derive(Debug, Clone)]
struct Round2Artifact<P: SchemeParams> {
beta: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
hat_beta: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
beta: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
hat_beta: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
r: Randomizer<P::Paillier>,
s: Randomizer<P::Paillier>,
hat_r: Randomizer<P::Paillier>,
Expand All @@ -435,8 +435,8 @@ struct Round2Artifact<P: SchemeParams> {

struct Round2Payload<P: SchemeParams> {
cap_gamma: Point,
alpha: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
hat_alpha: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
alpha: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
hat_alpha: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
cap_d: Ciphertext<P::Paillier>,
hat_cap_d: Ciphertext<P::Paillier>,
}
Expand Down Expand Up @@ -473,8 +473,8 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {

let target_pk = &self.context.public_aux(destination)?.paillier_pk;

let beta = Secret::init_with(|| Signed::random_bounded_bits(rng, P::LP_BOUND));
let hat_beta = Secret::init_with(|| Signed::random_bounded_bits(rng, P::LP_BOUND));
let beta = SecretSigned::random_in_exp_range(rng, P::LP_BOUND);
let hat_beta = SecretSigned::random_in_exp_range(rng, P::LP_BOUND);
let r = Randomizer::random(rng, pk);
let s = Randomizer::random(rng, target_pk);
let hat_r = Randomizer::random(rng, pk);
Expand All @@ -496,7 +496,7 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {
.all_cap_k
.get(destination)
.ok_or(LocalError::new("Missing destination={destination:?} in all_cap_k"))?
* secret_signed_from_scalar::<P>(&self.context.key_share.secret_share)
* &secret_signed_from_scalar::<P>(&self.context.key_share.secret_share)
+ Ciphertext::new_with_randomizer_signed(target_pk, &-&hat_beta, &hat_s);

let rp = &self.context.public_aux(destination)?.rp_params;
Expand Down Expand Up @@ -661,18 +661,10 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {
// `alpha == x * y + z` where `0 <= x, y < q`, and `-2^l' <= z <= 2^l'`,
// where `q` is the curve order.
// We will need this bound later, so we're asserting it.
let alpha = Secret::try_init_with(|| {
alpha
.expose_secret()
.assert_bit_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsAlpha))
})?;
let hat_alpha = Secret::try_init_with(|| {
hat_alpha
.expose_secret()
.assert_bit_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1)
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsHatAlpha))
})?;
let alpha = Option::from(alpha.ensure_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1))
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsAlpha))?;
let hat_alpha = Option::from(hat_alpha.ensure_bound(core::cmp::max(2 * P::L_BOUND, P::LP_BOUND) + 1))
.ok_or_else(|| ReceiveError::protocol(InteractiveSigningError::OutOfBoundsHatAlpha))?;

Ok(Payload::new(Round2Payload::<P> {
cap_gamma: direct_message.cap_gamma,
Expand All @@ -697,15 +689,15 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {

let cap_delta = cap_gamma * &self.context.k;

let alpha_sum: Secret<Signed<_>> = payloads.values().map(|payload| &payload.alpha).sum();
let beta_sum: Secret<Signed<_>> = artifacts.values().map(|artifact| &artifact.beta).sum();
let alpha_sum: SecretSigned<_> = payloads.values().map(|payload| &payload.alpha).sum();
let beta_sum: SecretSigned<_> = artifacts.values().map(|artifact| &artifact.beta).sum();
let delta = secret_signed_from_scalar::<P>(&self.context.gamma)
* secret_signed_from_scalar::<P>(&self.context.k)
+ &alpha_sum
+ &beta_sum;

let hat_alpha_sum: Secret<Signed<_>> = payloads.values().map(|payload| &payload.hat_alpha).sum();
let hat_beta_sum: Secret<Signed<_>> = artifacts.values().map(|artifact| &artifact.hat_beta).sum();
let hat_alpha_sum: SecretSigned<_> = payloads.values().map(|payload| &payload.hat_alpha).sum();
let hat_beta_sum: SecretSigned<_> = artifacts.values().map(|artifact| &artifact.hat_beta).sum();
let chi = secret_signed_from_scalar::<P>(&self.context.key_share.secret_share)
* secret_signed_from_scalar::<P>(&self.context.k)
+ &hat_alpha_sum
Expand Down Expand Up @@ -734,8 +726,8 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round2<P, I> {
#[derive(Debug)]
struct Round3<P: SchemeParams, I: Ord> {
context: Context<P, I>,
delta: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
chi: Secret<Signed<<P::Paillier as PaillierParams>::Uint>>,
delta: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
chi: SecretSigned<<P::Paillier as PaillierParams>::Uint>,
cap_delta: Point,
cap_gamma: Point,
all_cap_k: BTreeMap<I, Ciphertext<P::Paillier>>,
Expand Down Expand Up @@ -999,28 +991,28 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round3<P, I> {
// Mul proof
let my_id = &self.context.my_id;
let rho = Randomizer::random(rng, pk);
let cap_x = self
let cap_k = self
.all_cap_k
.get(my_id)
.ok_or_else(|| LocalError::new("my_id={my_id:?} is missing in all_cap_k"))?;
let cap_y = self
let cap_g = self
.all_cap_g
.get(my_id)
.ok_or_else(|| LocalError::new("my_id={my_id:?} is missing in all_cap_g"))?;
let cap_h = (cap_y * secret_bounded_from_scalar::<P>(&self.context.k)).mul_randomizer(&rho);
let cap_h = (cap_g * &secret_unsigned_from_scalar::<P>(&self.context.k)).mul_randomizer(&rho);

let p_mul = MulProof::<P>::new(
rng,
&secret_signed_from_scalar::<P>(&self.context.k),
&self.context.rho,
&rho,
pk,
cap_x,
cap_y,
cap_k,
cap_g,
&cap_h,
&aux,
);
assert!(p_mul.verify(pk, cap_x, cap_y, &cap_h, &aux));
assert!(p_mul.verify(pk, cap_k, cap_g, &cap_h, &aux));

// Dec proof

Expand Down Expand Up @@ -1229,7 +1221,7 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round4<P, I> {
let cap_x = self.context.public_share(&my_id)?;

let rho = Randomizer::random(rng, pk);
let hat_cap_h = (&self.presigning.cap_k * secret_bounded_from_scalar::<P>(x)).mul_randomizer(&rho);
let hat_cap_h = (&self.presigning.cap_k * &secret_unsigned_from_scalar::<P>(x)).mul_randomizer(&rho);

let aux = (&self.context.ssid_hash, &my_id);

Expand Down Expand Up @@ -1267,16 +1259,17 @@ impl<P: SchemeParams, I: PartyId> Round<I> for Round4<P, I> {
}

let r = self.presigning.nonce;
let signed_r = public_signed_from_scalar::<P>(&r);
let signed_message = public_signed_from_scalar::<P>(&self.context.message);

let ciphertext = ciphertext * bounded_from_scalar::<P>(&r)
+ &self.presigning.cap_k * bounded_from_scalar::<P>(&self.context.message);
let ciphertext = ciphertext * &signed_r + &self.presigning.cap_k * &signed_message;

let rho = ciphertext.derive_randomizer(sk);
// This is the same as `s_part` but if all the calculations were performed
// without reducing modulo curve order.
let s_part_nonreduced = secret_signed_from_scalar::<P>(&self.presigning.ephemeral_scalar_share)
* signed_from_scalar::<P>(&self.context.message)
+ self.presigning.product_share_nonreduced.clone() * signed_from_scalar::<P>(&r);
* signed_message
+ &self.presigning.product_share_nonreduced * signed_r;

let mut dec_proofs = Vec::new();
for id_l in self.context.other_ids.iter() {
Expand Down
Loading
Loading