-
Notifications
You must be signed in to change notification settings - Fork 322
ec: implement double-odd curves #986
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
base: master
Are you sure you want to change the base?
Conversation
As a side note: I recall a discussion on Discord where there was a parameter dump for a DO curve that embeds Curve25519, but I don't have the link at hand. Here are the SW parameters:
|
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.
Thanks for the PR! Left some comments!
Pushed a few fixups, will discuss the rest with @Tarinn when we both have time at the office! Thanks for the review so far. |
19b1822
to
e084df6
Compare
Implements Thomas Pornin's “A Prime-Order Group with Complete Formulas from Even-Order Elliptic Curves” [1], often referred to as "double odd" curves. Includes the double-odd curve “JQ255s” as presented in the paper. [1] T. Pornin, “A Prime-Order Group with Complete Formulas from Even-Order Elliptic Curves,” IACR CiC, vol. 1, no. 1, p. 33, Apr. 2024, doi: 10.62056/akmp-4c2h.
@Pratyush, @samvandevelde noticed that the current implementation was tailored to Jq255s, where A=-1. This has meanwhile been resolved (766b91a). He'll also take care of your further comments. Thanks for the feedback again, as always! |
use crate::{constraints::FqVar, *}; | ||
use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar; | ||
|
||
/// A group element in the Curve25519 curve. |
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.
Please update this comment.
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.
} | ||
|
||
#[test] | ||
fn valid_decode() { |
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 there a source for these test vectors? If so could you please add a link here?
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.
pub fn n() -> Self { | ||
Self { | ||
e: -P::BaseField::ONE, | ||
u: P::BaseField::ZERO, | ||
} | ||
} |
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.
What is the point represented by this function?
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.
ec/src/models/double_odd/affine.rs
Outdated
// Compute the curve equation x(x^2 + Ax + B). | ||
let e = (P::get_c() * u.square().square() - (P::COEFF_A * u.square()).double() | ||
+ P::BaseField::ONE) | ||
.sqrt()?; | ||
let neg_e = -e; | ||
match e < neg_e { | ||
true => Some((e, neg_e)), | ||
false => Some((neg_e, e)), | ||
} |
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 is this value for e
derived? It doesn't seem to match the curve equation?
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.
Dear Prof. Mishra,
The correct (Jacobi Quartic) equation has been provided in commit 572b797
Kind regards,
Sam
let e_squared = P::get_c() * self.u.square().square() | ||
- (P::COEFF_A * self.u.square()).double() | ||
+ P::BaseField::ONE; |
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.
Same here.
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.
Dear Prof. Mishra,
The correct (Jacobi Quartic) equation has been provided in commit 572b797
Kind regards,
Sam
} | ||
|
||
impl<P: DOCurveConfig, T: Borrow<Affine<P>>> AddAssign<T> for Projective<P> { | ||
fn add_assign(&mut self, other: T) { |
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.
Can you add a reference for this code? Perhaps a pointer to existing "projective + projective" formulae, along with a description of the simplification when one of the points is affine.
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.
Dear Prof. Mishra,
The missing reference to the addition formulae has been provided in commit 572b797
Kind regards,
Sam
if self.is_zero() { | ||
*self = *other; | ||
return; | ||
} | ||
|
||
if other.is_zero() { | ||
return; | ||
} | ||
|
||
let n1 = self.e * other.e; | ||
let n2 = self.z * other.z; | ||
let n3 = self.u * other.u; | ||
let n4 = self.t * other.t; | ||
|
||
let n5 = (self.z + self.t) * (other.z + other.t) - n2 - n4; | ||
self.t = (self.e + self.u) * (other.e + other.u) - n1 - n3; | ||
let c = P::get_c(); | ||
let cn4 = c * n4; | ||
self.z = n2 - cn4; | ||
|
||
let n3d = n3.double(); | ||
|
||
self.e = (n2 + cn4) * (n1 - P::COEFF_A * n3d) + c * n3d * n5; | ||
self.u = self.z * self.t; | ||
self.z.square_in_place(); | ||
self.t.square_in_place(); |
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.
Same here; please add a reference.
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.
Dear Prof. Mishra,
The missing reference to the addition formulae has been provided in commit 572b797
Kind regards,
Sam
match compress { | ||
Compress::Yes => { | ||
let mut buffer = ark_std::vec::Vec::new(); | ||
item.e.serialize_uncompressed(&mut buffer)?; | ||
if buffer[0] & 1u8 == 1u8 { | ||
-item.u | ||
} else { | ||
item.u | ||
} | ||
.serialize_uncompressed(writer) | ||
}, | ||
Compress::No => { | ||
item.e.serialize_with_mode(&mut writer, compress)?; | ||
item.u.serialize_with_mode(&mut writer, compress) | ||
}, | ||
} |
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.
Could you provide a reference as to how this matches up with the official encoding described in Section 6.1.1 of https://doubleodd.group/doubleodd.pdf?
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.
Dear Prof. Mishra,
The referenced official encoding was for do255e and do255s only (and rephrased in the follow-up paper for jq255e/s, https://doubleodd.group/doubleodd-jq.pdf page 23). However, was meant to standardize encoding for these specific curves, so it seemed too specific to add in the comments of the model for all double odd curves.
That being said, I compared the specifications with the arkworks implementation of these operations for Fp,
and Fp matches up with the described encoding (see below).
Should these results perhaps be writen in the comments of algebra/curves/jq255s instead?
Kind regards,
Sam
- A field element x ∈ Fq is considered as an integer in the 0 to q − 1 range, which is then encoded using the unsigned little-endian convention (least significant byte comes first).
OK: Serialization of Fp uses copy_from_u64_slice(), which uses from_le_bytes.
- Encoding always uses 32 bytes, even if the integer could have fit into fewer bytes
OK: Without any flags, 32 bytes are used for the q and r described in the paper.
- Decoders MUST reject the source bytes, and return Invalid, if any of the following conditions hold:
• The source length is not exactly 32 bytes.
• The integer resulting from unsigned little-endian interpretation of the source bytes is not in the 0 to q − 1 range.
In particular, there is no ignored bit: even though the value of q implies that the most significant bit of the last byte is always zero, that bit MUST NOT be ignored by decoders. Moreover, checking that the most significant bit of the last byte is zero is not sufficient validation; for instance, an encoding of the integer q itself, over 32 bytes, MUST be rejected as Invalid, since it is not in the 0 to q − 1 range. There is no implicit reduction modulo q.
OK: Deserialization to Fp uses from_bigint(), which returns an Option depending on is_geq_modulus(), as well as from_le_bytes(), over the entirety of the 32 bytes (fixed to 32 by read_exact_up_to(...,output_byte_size))
ec/src/models/double_odd/mod.rs
Outdated
let e: Self::BaseField = (Self::get_c() * u.square().square() | ||
- (Self::COEFF_A * u.square()).double() | ||
+ Self::BaseField::ONE) | ||
.sqrt() | ||
.ok_or(SerializationError::InvalidData) | ||
.unwrap(); |
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.
Could this be deduplicated by calling the get_e_from_u_unchecked
fn on Affine
?
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.
Dear Prof. Mishra,
The missing reference to the addition formulae has been provided in commit f75be11
Kind regards,
Sam
Although the same value, this rewrite more clearly indicates the value of COEFF_A (equal to -1 as described in https://eprint.iacr.org/2022/1052) Co-authored-by: Pratyush Mishra <pratyush795@gmail.com>
0d98c43
to
f75be11
Compare
Implements Thomas Pornin's “A Prime-Order Group with Complete Formulas from Even-Order Elliptic Curves” [1], often referred to as "double odd" curves.
Includes the double-odd curve “JQ255s” as presented in the paper.
[1] T. Pornin, “A Prime-Order Group with Complete Formulas from Even-Order Elliptic Curves,” IACR CiC, vol. 1, no. 1, p. 33, Apr. 2024, doi: 10.62056/akmp-4c2h.
This is work by @Tarinn
Description
closes: #490
Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.
Pending
section inCHANGELOG.md
Files changed
in the GitHub PR explorer