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

Remove slip10-like derivation and add stark-specific derivation #14

Merged
merged 8 commits into from
Dec 4, 2024
Merged

Conversation

survived
Copy link
Contributor

@survived survived commented Nov 19, 2024

  • Remove slip10-like derivation that can be instantiated with any curve: it is very inefficient
    when instantiated with certain curves, and may also enable attacker to perform DoS attack by
    finding derivation path that results into very long computation
  • Add stark-specific derivation: secure and efficient derivation for stark curve

Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
Signed-off-by: Denis Varlakov <[email protected]>
@survived survived changed the title Add curves analysis Remove slip10-like derivation and add stark-specific derivation Nov 25, 2024
@survived survived requested a review from maurges November 29, 2024 08:55
@survived survived marked this pull request as ready for review November 29, 2024 08:56
order_minus_one + 1
};
let order_log2 = order.significant_bits();
let l: rug::Integer = rug::Rational::from((order_log2 + 128, 8)).ceil_ref().into();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not (order_log2 + 128 + 7) / 8?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to explicitly use ceiling function to have less opportunities to mess up, and to match the formula from RFC precisely

Comment on lines +125 to +131
for (lo, hi) in (1..).zip(0..) {
let x_lo = rug::Rational::from((rug::Integer::ONE, rug::Integer::ONE << lo));
let x_hi = rug::Rational::from((rug::Integer::ONE, rug::Integer::ONE << hi));
if x_lo <= *x && *x <= x_hi {
return (lo, hi);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need two variables here: as soon as x_lo <= x you can take hi = lo - 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What you suggest is supposed to decrease amount of the code, but adding let hi = lo - 1 actually adds extra line of code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(if I correctly understood what you suggested)

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I'm suggesting reducing the amount of computation done, not necessarily code. You remove hi in the loop, you remove x_hi altogether, and when the comparison succeeds, you compute hi = lo - 1. By my calculations, the amount of lines of code will stay the same, but the lines will get shorter and we drop one comparison

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if $2^{-k} \le x$, that does not necessarily mean that $x \le 2^{-k+1}$ in general. That’s probably true from the fact that we check that $0 &lt; x &lt; 1$, but again, in this tool I prefer to double check everything, because we do complex computations and it’s essential to be assured that everything is correct. I prioritize auditability/readability here over performance/allocations

Copy link
Contributor

Choose a reason for hiding this comment

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

In general no, but the loop finds not a general k, but a minimal k such that $x \le 2^{-k}$. Since it's minimal, it follows that $x &gt; 2^{-(k - 1)}$.

Reformulating imperatively, you're iterating lo <- [1, 2, ..], you compute x_lo = 1 / (1 << lo). You condition for breaking is x_lo <= x. that means if you're evaluating the loop, you have x_lo' = 1 / (1 << (lo - 1)) and x_lo' > x. Note that this x_lo' is exactly x_hi.

What it means is that you can skip comparing x_hi, and move computing x_hi altogether into the same branch as return.

Copy link
Contributor

Choose a reason for hiding this comment

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

I get your view about not optimizing much for performance, since it's a piece of code ran rarely. But also when I first saw it, it took me some time to verify that hi is indeed computed from k-1, so readability gain here is dubious

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here's my logic: when I see in the output of the program that "stat diff lies in $2^{-k} \le x \le 2^{-k+1}$", my first thought is to check if it's correct. Suppose $x$ is calculated correctly, I need to check if boundaries are correct as well. To do that, I have to analyze the function. Right now, it's very easy to check that boundaries are identified correctly, as the only way this function returns something is when the condition $2^{-k} \le x \le 2^{-k+1}$ is true:

let x_lo = rug::Rational::from((rug::Integer::ONE, rug::Integer::ONE << lo));
let x_hi = rug::Rational::from((rug::Integer::ONE, rug::Integer::ONE << hi));
if x_lo <= *x && *x <= x_hi {
return (lo, hi);
}

So that's very easy to audit and analyze. If we do what you suggested, in my opinion, it will be more difficult to analyze the function, as it's now required to understand how the loop works. As you said, in general, this approach does not yield correct result, but it does in this particular case, and it will take some time to come to the same conclusion.

In this case, I want to keep the option that looks correct right away,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But also when I first saw it, it took me some time to verify that hi is indeed computed from k-1

How come? It's very clearly defined in the loop that lo goes in 1.. while hi goes in 0..

Comment on lines +109 to +110
let i = generic_array::sequence::Concat::concat(i0, i1);
let (shift, chain_code) = split(&i);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, why is concatenation not done in the calling function? Does this optimize better?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To have less of repeating code. Two different function are calling this one, if we were doing concat in the calling functions, we needed to write concat twice.

Copy link
Contributor

Choose a reason for hiding this comment

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

But this way you leak implementation details! It's not a big problem since it's an internal function, but it looks like a bizzare choice to me to mangle the domains like this to save one (1) line

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since it's an internal function, it's not leaking implementation detail

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dunno, it feels like a natural choice for me...

src/stark.rs Show resolved Hide resolved
Copy link
Contributor

@maurges maurges left a comment

Choose a reason for hiding this comment

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

You know, other than your weird new obsession with saving single lines of code, the maths and the changes look good

@survived
Copy link
Contributor Author

survived commented Dec 2, 2024

I'm not obsessed with saving single lines of code, I'm lazy to change something unless I see a good motivation for that change :)

@survived survived merged commit c0053fb into m Dec 4, 2024
15 checks passed
@survived survived deleted the dt branch December 4, 2024 12:17
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