Correct decoding identity for embedwards25519/secq256k1

This commit is contained in:
Luke Parker
2025-01-29 23:01:45 -05:00
parent 2bc880e372
commit 315d4fb356
4 changed files with 14 additions and 6 deletions

View File

@@ -7,7 +7,7 @@ This curve was found via
for finding curves (specifically, curve cycles), modified to search for curves for finding curves (specifically, curve cycles), modified to search for curves
whose field is the Ed25519 scalar field (not the Ed25519 field). whose field is the Ed25519 scalar field (not the Ed25519 field).
``` ```ignore
p = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed p = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
q = 0x0fffffffffffffffffffffffffffffffe53f4debb78ff96877063f0306eef96b q = 0x0fffffffffffffffffffffffffffffffe53f4debb78ff96877063f0306eef96b
D = -420435 D = -420435

View File

@@ -198,6 +198,7 @@ impl Group for Point {
Point { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ZERO } Point { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ZERO }
} }
fn generator() -> Self { fn generator() -> Self {
// Point with the lowest valid x-coordinate
Point { Point {
x: FieldElement::from_repr(hex_literal::hex!( x: FieldElement::from_repr(hex_literal::hex!(
"0100000000000000000000000000000000000000000000000000000000000000" "0100000000000000000000000000000000000000000000000000000000000000"
@@ -335,8 +336,10 @@ impl GroupEncoding for Point {
// If this the identity, set y to 1 // If this the identity, set y to 1
let y = let y =
CtOption::conditional_select(&y, &CtOption::new(FieldElement::ONE, 1.into()), is_identity); CtOption::conditional_select(&y, &CtOption::new(FieldElement::ONE, 1.into()), is_identity);
// If this the identity, set y to 1 and z to 0 (instead of 1)
let z = <_>::conditional_select(&FieldElement::ONE, &FieldElement::ZERO, is_identity);
// Create the point if we have a y solution // Create the point if we have a y solution
let point = y.map(|y| Point { x, y, z: FieldElement::ONE }); let point = y.map(|y| Point { x, y, z });
let not_negative_zero = !(is_identity & sign); let not_negative_zero = !(is_identity & sign);
// Only return the point if it isn't -0 // Only return the point if it isn't -0

View File

@@ -192,6 +192,7 @@ impl Group for Point {
Point { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ZERO } Point { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ZERO }
} }
fn generator() -> Self { fn generator() -> Self {
// Point with the lowest valid x-coordinate
Point { Point {
x: FieldElement::from_repr( x: FieldElement::from_repr(
hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000001") hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000001")
@@ -334,8 +335,10 @@ impl GroupEncoding for Point {
// If this the identity, set y to 1 // If this the identity, set y to 1
let y = let y =
CtOption::conditional_select(&y, &CtOption::new(FieldElement::ONE, 1.into()), is_identity); CtOption::conditional_select(&y, &CtOption::new(FieldElement::ONE, 1.into()), is_identity);
// If this the identity, set y to 1 and z to 0 (instead of 1)
let z = <_>::conditional_select(&FieldElement::ONE, &FieldElement::ZERO, is_identity);
// Create the point if we have a y solution // Create the point if we have a y solution
let point = y.map(|y| Point { x, y, z: FieldElement::ONE }); let point = y.map(|y| Point { x, y, z });
let not_negative_zero = !(is_identity & sign); let not_negative_zero = !(is_identity & sign);
// Only return the point if it isn't -0 and the sign byte wasn't malleated // Only return the point if it isn't -0 and the sign byte wasn't malleated

View File

@@ -154,18 +154,20 @@ pub fn test_group<R: RngCore, G: Group>(rng: &mut R) {
/// Test encoding and decoding of group elements. /// Test encoding and decoding of group elements.
pub fn test_encoding<G: PrimeGroup>() { pub fn test_encoding<G: PrimeGroup>() {
let test = |point: G, msg| { let test = |point: G, msg| -> G {
let bytes = point.to_bytes(); let bytes = point.to_bytes();
let mut repr = G::Repr::default(); let mut repr = G::Repr::default();
repr.as_mut().copy_from_slice(bytes.as_ref()); repr.as_mut().copy_from_slice(bytes.as_ref());
assert_eq!(point, G::from_bytes(&repr).unwrap(), "{msg} couldn't be encoded and decoded"); let decoded = G::from_bytes(&repr).unwrap();
assert_eq!(point, decoded, "{msg} couldn't be encoded and decoded");
assert_eq!( assert_eq!(
point, point,
G::from_bytes_unchecked(&repr).unwrap(), G::from_bytes_unchecked(&repr).unwrap(),
"{msg} couldn't be encoded and decoded", "{msg} couldn't be encoded and decoded",
); );
decoded
}; };
test(G::identity(), "identity"); assert!(bool::from(test(G::identity(), "identity").is_identity()));
test(G::generator(), "generator"); test(G::generator(), "generator");
test(G::generator() + G::generator(), "(generator * 2)"); test(G::generator() + G::generator(), "(generator * 2)");
} }