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

Generic FMD2 implementation #18

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

larraia
Copy link
Contributor

@larraia larraia commented Feb 4, 2025

Refactor code. Re-uses internally the same FMD2 implementation for vanilla FMD2 and the polynomial-base FMD2. (Mainly, code just moved around.)

Needed for PR #19

Copy link
Collaborator

@XuyangSong XuyangSong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run cargo fmt before merging. We currently lack a CI for reporting format issues.

Comment on lines 48 to 63
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// γ secret keys (scalars). For minimum false-positive rate p:=2^{-γ}.
pub struct SecretKey(pub(crate) Vec<Scalar>);

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
/// A subset of n-out-γ secret keys and the positions
/// they occupy in [SecretKey].
pub struct DetectionKey {

pub(crate) keys: Vec<Scalar>,

pub(crate) indices: Vec<usize>,

}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason to move the curve25519-based SecretKey and DetectionKey implementations here? In lib.rs, it appears you are defining the general FMD interfaces.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the SecretKey and DetectionKey structs and methods be in the same file, or do you have other reasons to separate them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason to move the curve25519-based SecretKey and DetectionKey implementations here? In lib.rs, it appears you are defining the general FMD interfaces.

I moved SecretKey and DetectionKey out of the vanilla FMD2 implementation because they will also be used by the Fmd2Poly implementation.

The trait FmdScheme uses these two structs, (as opposed to PublicKey, FlagCiphertext that are implementation-dependent.)

Could the SecretKey and DetectionKey structs and methods be in the same file, or do you have other reasons to separate them?

Yes, ideally everything in the same file. Perhaps we can find a better location than lib.rs? -- suggestions welcome.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move the SecretKey and DetectionKey along with their methods to separate files(keys.rs or secret_key.rs and detection_key.rs) instead of keeping them in lib.rs?

}
}

/// FMD2 is proven to be IND-CCA secure in the [FMD paper](https://eprint.iacr.org/2021/089).
impl CcaSecure for Fmd2 {}
impl CcaSecure for Fmd2Params {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is CcaSecure a todo feature? I noticed it's empty

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a marker trait to signal the scheme is IND-CCA. We can remove it if it is confusing.

Copy link
Member

@batconjurer batconjurer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also like to see unit tests of the diversified keys.

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SecretKey(Vec<Scalar>);
use crate::{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to suggest we use the same import format as Namada. There are three import blocks: First is from core, std, alloc, etc. The second is third party. The last is crate, super, etc. There should a single return between blocks, and no returns within a block. Each block should be alphabetized

use crate::DetectionKey;

#[derive(Debug, Clone)]
pub(crate) struct GenericPublicKey {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would prefer to call this a DiversifiedPublicKey to match the terminology elsewhere.

}

#[derive(Debug, Clone)]
pub(crate) struct GenericFlagCiphertexts {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar nit as before: DiversifiedFlagCiphertexts


GenericFlagCiphertexts::generate_flag(
&gpk,
&TrapdoorBasepoint::new(&gpk, &Scalar::ONE),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can have an impl From<GenericPublicKey> for this case. Or even a Default impl'd for TrapdoorBasepoint

}

pub(crate) struct TrapdoorBasepoint {
b: RistrettoPoint,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's give these fields more descriptive names. Maybe something like base and exp. But one letter fields are starting to confuse me as I review other parts of the code.

pub(crate) fn new(pk: &GenericPublicKey, trapdoor: &Scalar) -> TrapdoorBasepoint {
TrapdoorBasepoint {
b: pk.basepoint_eg * trapdoor,
t: *trapdoor,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through penumbra's specs, they don't require this trapdoor. They use randomize the pk's basepoint with two different random scalars. Why can't we just do the same?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants