Skip to content

CSIDH#1

Open
AndHell wants to merge 20 commits into
GiacomoPope:mainfrom
AndHell:csidh
Open

CSIDH#1
AndHell wants to merge 20 commits into
GiacomoPope:mainfrom
AndHell:csidh

Conversation

@AndHell

@AndHell AndHell commented Jun 2, 2025

Copy link
Copy Markdown

In this PR, we provide a simplified implementation of the CSIDH protocol using the CSIDH-512 parameter set.

It is simplified in the sense that it is not fully optimized, but focuses on the readability of the different steps in the protocol.

Further todos:

  • switch to velusqrt
  • implement verification

@GiacomoPope GiacomoPope left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Some small comments, but otherwise thank you so much!

Comment thread src/elliptic/curve.rs Outdated
let Y = V * XZ;
let ok = Y.is_square();

(P, ok)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This function should simply be a call to rand_point to get a valid point, then we should use to_pointx. Something like:

pub fn rand_pointx<R: CryptoRng + RngCore>(&self, rng: &mut R) -> PointX {
    let P = Self::rand_point(rng);
    P.to_pointx()
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I see that this method uses failure for the direction in CSIDH reading some more, but I think this then really needs to be a method for CSIDH rather than on the Curve type, as wanting a point on the twist instead of the curve seems a little esoteric?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Maybe we want something like rand_point on the Csidh type and then we return `P, twist) to make it obvious what we're doing for this case?

Comment thread src/protocols/csidh.rs Outdated

#[derive(Clone, Copy, Debug)]
pub struct CsidhParameters<const COUNT: usize> {
pub num_primes: usize,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

is num_primes not just the same as COUNT?

Comment thread src/protocols/csidh.rs Outdated

}

// // For extra safty, assert the kernel is indeed of the correct degree

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
// // For extra safty, assert the kernel is indeed of the correct degree
// // For extra safety, assert the kernel is indeed of the correct degree

Comment thread src/protocols/csidh.rs

// check if the kernel is of the correct degree
// if not we skip it and try again on an new round
if K.is_zero() == u32::MAX {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Feels like this continue should somehow be linked in to cofactor clearing, otherwise you might have P = 0 after an evaluation and yet you spend all that time cofactor clearing only to exit afterwards.

Comment thread src/protocols/csidh_parameters.rs Outdated
];

pub const CSIDH_PARAMS: CsidhParameters<NUM_PRIMES> = CsidhParameters {
num_primes: NUM_PRIMES,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

yeah this can be cleaned up, we dont need num_primesas we can just useNUM_PRIMES`

Comment thread src/protocols/csidh.rs Outdated
let (mut P, direction) = curve.rand_pointX(rng);
let direction = direction == 0;

// clear cofactor

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
// clear cofactor
// clear 2^e cofactor

Comment thread src/protocols/csidh.rs Outdated
private_key: &CsidhPrivateKey<COUNT>,
rng: &mut R,) -> CsidhPublicKey<Fp> {

// todo: verify

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

shall we ust multiply by (p+1) a bunch of times to check supersingularity?

@GiacomoPope

Copy link
Copy Markdown
Owner

I'm back from leave now, did you have time to work on the comments, or would you like me to merge as is and do edits myself?

Comment thread src/elliptic/point.rs Outdated
}

/// Return a new random X only point.
pub fn rand_point<R: CryptoRng + RngCore>(rng: &mut R) -> PointX<Fq> {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This doesnt always return a valid point on the curve... I think we should just delete this for now as it might be confusing?

Comment thread src/protocols/csidh.rs Outdated
use rand_core::{CryptoRng, RngCore};

#[derive(Clone, Copy, Debug)]
pub struct CsidhParameters<const COUNT: usize> {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

maybe rename to PRIMES or PRIME_COUNT?

Comment thread src/protocols/csidh.rs
Comment thread src/protocols/csidh.rs Outdated
Comment thread src/fields/csidh.rs Outdated



fp2::define_fp2_from_modulus!(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We dont need the extension, right? We can use define_fp_core https://docs.rs/fp2/latest/fp2/macro.define_fp_core.html

max_exponent: MAX_EXPONENT,
two_cofactor: COFACTOR,
primes: PRIMES,
four_sqrt_p: FOUR_SQRT_P,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Cant we have this value as a Fp and then avoid the need for , 5? Similar to how we have constants in the sidh impl

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, this part is quite ugly.

The issue is that we need 4sqrt(p) as a bigint (bn), not as a Fp, in the verification, to check against the order of the random point.
The cleanest way would probably be to have a struct for bn.

I'll try to come up with something.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We do we need it to be a big number? For scalar multiplication? One option would be to use a Fp element and then encode this to bytes for scalar multiplication? Another, yes, would be to make a BN type

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We only use this constant to check if the order of a point is > 4sqrt(p).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Oh I see, this is alg 2 of (https://eprint.iacr.org/2022/880.pdf)...

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think the "best" method at the moment is have $4 \sqrt{p}$ as a Fp type in the structure and then in verify we can do something like

    bound = bytes_to_bn_vartime(&self.four_sqrt_p.encode())

where &self.four_sqrt_p.encode() will have type &[u8] and bytes_to_bn_vartime can convert from base 2^8 to base 2^64?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I ended up adding a small Bn struct as a wrapper.
Let me know what you think about this approach.
If you think it's suitable I can also extend the struct.

Comment thread src/protocols/csidh.rs Outdated

// if RHS i a sqrt, it is on the curve
let RHS = (Cxx+four_Ax-two_Cx+(*C24))*x;
let (_, is_sqrt) = RHS.sqrt();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Comment thread src/protocols/csidh.rs
let four_Ax = tmp+tmp;
// projective curve: x^3C+4Ax^2−2x^2C+XC​
let tmp = *A24*x;
let four_Ax = tmp+tmp+tmp+tmp;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

we have a mul4() method available in fp2_rs

Comment thread src/protocols/csidh.rs
let four_Ax = tmp+tmp+tmp+tmp;
let tmp = *C24*x;
let Cxx = tmp*x;
let two_Cx = tmp+tmp;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same here, we have a mul2()

Comment thread src/protocols/csidh.rs Outdated
let A24 = public_key.A + Fp::TWO;
let C24 = Fp::FOUR;

let fsqrtp = &self.four_sqrt_p.limbs[..self.four_sqrt_p.len];

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This looks like we might want to make a method out of it? maybe a Bn to_slice() ?

0x856f1399d91d6592,
0x0000000000000002,
];
0x0000000000000000,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

why the extra 0x00?

Comment thread src/utilities/bn.rs Outdated


// This is a small wrapper to use a bn as constant
const BN_MAXLIMBS : usize = 8;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

oooh this is why... Maybe we should use a vector and dynamically allocate? This could be refactored later I suppose though.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Vectors and constants don't like each other much.

What about putting Bn behind a macro, similar to Fp?
It's quite a bit of overhead for a single constant, but it should be the cleanest solution and might be helpful for other protocols.

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.

2 participants