-
Notifications
You must be signed in to change notification settings - Fork 11
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
Updates for CGGMP'24 #170
base: master
Are you sure you want to change the base?
Updates for CGGMP'24 #170
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #170 +/- ##
==========================================
+ Coverage 92.46% 95.89% +3.43%
==========================================
Files 35 37 +2
Lines 7030 9454 +2424
==========================================
+ Hits 6500 9066 +2566
+ Misses 530 388 -142 ☔ View full report in Codecov by Sentry. |
12afc7a
to
e0565ce
Compare
cdb7c84
to
0ca10d8
Compare
0fc38fb
to
235afa0
Compare
3efcfd4
to
0f86f18
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have looked at Key_init and Key_refresh tests only.
As mentioned I think it's very cool to see the fault injection machinery come together, it's going to be a major help. The code is verbose and repetitive at times, but this is a complex protocol and its tests are always going to reflect that complexity.
Having the right testing tools is about finding that delicate balance between readability&maintainability and expressiveness. I'm sure we'll fiddle with this plenty mroe in the future but this strikes me as much better than we had before.
.collect() | ||
} | ||
|
||
fn check_evidence<M>(expected_description: &str) -> Result<(), LocalError> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming nitpick: this does more than merely checking some data against some other; it actually drives the protocol (and checks the outcome). In my head "check" is more "compare these two things and yell if they don't match".
How about a refactor to something more classic like "let r: Result<…, …> = run(); assert_eq!(r, …, "bla bla");"?
Less invasively: a rename to assert_outcome(expected)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a refactor to something more classic like "let r: Result<…, …> = run(); assert_eq!(r, …, "bla bla");"?
It checks a number of things internally:
- the malicious node does not create any malicious behavior evidence
- all the other nodes create an evidence for the malicious node
- the evidence description matches the expected one
Not sure if it's worth packing in one variable.
|
||
fn check_evidence<M>(expected_description: &str) -> Result<(), LocalError> | ||
where | ||
M: Misbehaving<Id, (), EntryPoint = KeyRefresh<P, Id>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a pity that check_evidence
and make_entry_points
have to be instantiated for each EntryPoint. As a new reader of the code, I have to look rather carefully before I spot that this one is for KeyRefresh
and the other is KeyInit
.
Maybe we can have a macro at some point to make the critical parts more visible, e.g.:
check_evidence!(KeyInit, …, …);
check_evidence!(KeyRefresh, …, …);
EP: 'static + Debug + EntryPoint<SP::Verifier>, | ||
SP: SessionParameters, | ||
{ | ||
let prefix = match part { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, but maybe "phase" is more descriptive than "part" here? ModifyPhase
and CheckPhase
etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not really a phase, since they are delivered simultaneously. It mimics the ProtocolMessagePart
terminology from manul
9a937ba
to
d3a940f
Compare
To replace the old dec when we are converting Presigning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review of PAPER.md
and README.md
|
||
Q: In Fig. 5 the initial commitment in the Schnorr proof (`A_i`) is sent twice (in R2 and then R3, as a part of `psi_i`), and then the equality of those two values is checked in Output, right before checking the proof itself. But the commitment value is used right after that in the `vrfy` step, so if it doesn't match the rest of the proof, the verification will fail. So is there any security reason for sending the commitment twice? (I understand that it does constitute a minor performance optimization) | ||
The above item leads to another problem. If those values are indeed echo-broadcasted, what malicious actions of one node can lead to passing the `П^{dec}` check on other nodes, but failing one of the `П^{aff-g*}` ones? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a little bit concerning. Something worth asking the authors directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did, about a week ago (along with sending them the list of all the other new typos). No response yet.
I guess it's not concerning for them since it's an extra check, not a missing check, so it doesn't compromise the security. But it is concerning for me since I can't test it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it sort of hinges on whether we're interested in provable aborts. The authors always talk about identifiable aborts only, which don't need echo-broadcasting of those values, so these checks may be needed to make the П^{aff-g*}
aborts identifiable. But my understanding is that we do want provable aborts (which I questioned in entropyxyz/manul#39), so I'm operating based on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed aff_g_star.rs
elements: Box<[AffGStarProofElement<P>]>, | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really ok to crash the whole process when this happens? I mean maybe it is, but perhaps it's a design constraint we should make very clear that we're making: when synedrion
encounters a catastrophic error (a bug) it will go down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment supposed to be attached to the assertions at the start of new()
? I thought about it myself, and actually thought I filed an issue about it, but I guess I haven't. Filed #181
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR though.
|
||
let cap_a = (public.cap_c * &alpha + Ciphertext::new_with_randomizer(public.pk0, &beta, &r)).to_wire(); | ||
let cap_r = secret_scalar_from_signed::<P>(&alpha).mul_by_generator(); | ||
let cap_b = Ciphertext::new_with_randomizer(public.pk1, &beta, &s).to_wire(); | ||
|
||
let ephemeral = AffGStarProofEphemeral::<P> { alpha, beta, r, s }; | ||
let commitment = AffGStarProofCommitment { cap_a, cap_r, cap_b }; | ||
|
||
(ephemeral, commitment) | ||
}) | ||
.unzip(); | ||
|
||
let mut reader = XofHasher::new_with_dst(HASH_TAG) | ||
// commitments | ||
.chain(&commitments) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the Shamir transform right? How can I double check (against the paper?) that we actually have all the data that we need baked into the reader? Does the order of the params matter here you reckon?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, Shamir transform. That's described in Section 3.4.1. x
there are the public parameters, and w
are the secret parameters. So as far as I understand it, it prescribes hashing both the public parameters and the commitment into the challenge.
Ideally I think we should have the corresponding public parameters struct to implement Hashable
, that will remove the need for duplication of the parameter list.
As for the order, I don't think it matters, it's a hash after all. As long as it's the same on both sides.
Fixes #157
Fixes #43
Fixes #91
Fixes #5 (in progress)
PAPER.md
, removed obsolete items.±2^l
now means[-2^(l-1)+1, 2^(l-1)]
instead of the previous[-2^l, 2^l]
). This caused a bit of a chain reaction:SecretSigned::assert_exponent_range()
logic changed.SecretSigned::random_in_exp_range*()
logic changed, and alsoexp
was changed toexponent
to match the assertion name.PublicSigned::from_xof_reader_bounded()
changed its behavior to produce the number according to the new range definition, and was renamed tofrom_xof_reader_in_range()
.PublicSigned::in_range_bits()
changed its behavior according to the new range definition, and was renamed tois_in_exponent_range()
.Ciphertext
constructor they are passed asSecretSigned
, to comply with the range requirements in the proofs.conversions::secret_unsigned_from_scalar()
removed.SecretSigned::new_modulo()
constructor to make a signed number in range [-N/2, N/2] from an Uint in range [0, N).Ciphertext::new()
anddecrypt()
(which took unsigned plaintexts), renamednew_signed()
anddecrypt_signed()
tonew()
anddecrypt()
.Ciphertext::new_with_randomizer()
was renamed tonew_with_randomizer_unsigned()
, since it's now a special one, only used in P_mul. Renamednew_with_randomizer_signed()
tonew_with_randomizer()
, andnew_public_with_randomizer_signed()
tonew_public_with_randomizer()
.e <-- ±q
is used, we are sampling the challenge as aScalar
using the newScalar::from_xof_reader()
method (and using that inП^sch
as well).aff-g
proof.prm
proof, and started usingBitVec
for its commitment.dec
proof (there were significant changes). Temporarily, it is located indec_new.rs
, will be moved todec.rs
whenPresigning
is updated.elog
proof.enc-elg
proof.aff-g*
proof.fac
proof, and implemented necessary changes to the algorithm (some variables are calculated differently, and the challenge is now a signedUint
and not aScalar
)mod
proof, and enforced invertibility conditions that were added in '24sch
proofenc
,log*
,mul
,mul*
proofs - they are not used anymore.IsInvertible
trait, documenting the choice between GCD andinvert()
TODO: