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

Routines for working with threshold signatures #138

Merged
merged 2 commits into from
May 10, 2022
Merged

Conversation

zah
Copy link
Contributor

@zah zah commented May 5, 2022

Other changes:

Cosmetic fixes bringing the project closer to the
Status style guide.

zah added 2 commits May 9, 2022 15:16
Other changes:

Cosmetic fixes bringing the project closer to the
Status style guide.
@zah zah merged commit 1d42842 into master May 10, 2022
@zah zah deleted the key-splitting-rebased branch May 10, 2022 00:32
export exportUncompressed
export
exportUncompressed,
ID, recover, genSecretShare, fromUint32, add
Copy link
Contributor

Choose a reason for hiding this comment

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

I think add is a problematic proc name in a security sensitive context, it makes it really hard to grep it or find out what collection it actually operates on.
The argument that it allows generic processing is moot because there is likely no reason to have something generic over a seq a table and say a polynomial.

func fromP2*(s: typedesc[Signature], pt: blst_p2): Signature =
var transformed: blst_p2_affine
transformed.blst_p2_to_affine(pt)
Signature(point: transformed)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would be very wary about returning large types on the stack, especially the SecretKey.

Nim used to (or still does) not optimize correctly the allocation with extra copies or zeroMem (flaky RVO or NRVO).

a.blst_p2_mult(a, s.toScalar(), 255)

func `*`(a: blst_p2; s: blst_fr): blst_p2=
result.blst_p2_mult(a, s.toScalar(), 255)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same remark, returning large values should be avoided for internal implementations, it's unnecessary costly in terms of stack space if RVO or NRVO fails.

A result allocation, a zeroMem
image
And then another copy at call site:
image

See also:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Frankly, this looks like a problem that's trivial to fix in Nim. It's a bit sad that it's informing the design of blscurve and Constantine.

func toP2(s: Signature): blst_p2 =
result.blst_p2_from_affine(s.getPoint)

func add*(a: SecretKey, b: SecretKey): SecretKey =
Copy link
Contributor

Choose a reason for hiding this comment

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

A function operating on a secret key should not be called add.

func add*(a: SecretKey, b: SecretKey): SecretKey =
var r: blst_fr
blst_fr_add(r, a.toFr, b.toFr)
SecretKey.fromFr(r)
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary copies, we can directly add in the buffer

# We will calculate a0 + X(a1 + X(a2 + ..X(an-1 + Xan))
var y = cfs[count - 1]
for i in 2 .. count:
y = y * x + cfs[count - i]
Copy link
Contributor

Choose a reason for hiding this comment

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

Lots of extra stack space used here


return y

func lagrangeInterpolation[T, U](yVec: openArray[T], xVec: openArray[U]): Result[T, cstring] =
Copy link
Contributor

Choose a reason for hiding this comment

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

Result is not cryptographically hardened, a better API here would be to return an enum and have the result be a var parameter.
It also adds to the large copies issue.

SecretKey.fromFr evaluatePolynomial(cfs, id.toFr)

func recover*(secrets: openArray[SecretKey],
ids: openArray[ID]): Result[SecretKey, cstring] =
Copy link
Contributor

Choose a reason for hiding this comment

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

SecretKeys should not go through Result

## Recover original secret key from N points generated by genSecretShare
let ys = secrets.mapIt(it.toFr)
let xs = ids.mapIt(it.toFr)
ok SecretKey.fromFr(? lagrangeInterpolation(ys, xs))
Copy link
Contributor

Choose a reason for hiding this comment

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

Heap allocation of secret data can and should be avoided here. A for-loop is enough.

## produced by at least N different secret shares generated by genSecretShare
let ys = signs.mapIt(it.toP2)
let xs = ids.mapIt(it.toFr)
ok Signature.fromP2(? lagrangeInterpolation(ys, xs))
Copy link
Contributor

Choose a reason for hiding this comment

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

Extra unnecessary heap allocation

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.

3 participants