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

Add BLS Elliptic Curve support in Cryptol #14

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
72 changes: 72 additions & 0 deletions spec/Spec/BlsHelpers.cry
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* The module contains functions that perform BLS operations.
* @see https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md#bls12-381-helpers
*/
module Spec::BlsHelpers where

import Common::Utils

/**
* BLS field elements are 256-bits long.
* @see https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md#custom-types
*/
type BlsFieldSize = 256
type BlsFieldElement = [BlsFieldSize]
Comment on lines +13 to +14
Copy link
Collaborator

Choose a reason for hiding this comment

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

question: BLS field elements are in the integers mod group w.r.t. the BLS modulus, right? Did you consider using Cryptol's integer mod group Z? I have a vague sense that it makes the SMT constraints a bit messier but it might simplify some of the code in here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I just learned about Z. I had previously missed it in the manual.


/**
* Specified by the consensus-specs.
* @see https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md#constants
*/
BLS_MODULUS : BlsFieldElement
BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513

NEGATIVE_ONE : BlsFieldElement
NEGATIVE_ONE = -1

/**
* Compute the modular inverse of x
* i.e. return y such that x * y % BLS_MODULUS == 1
* Precondition: x != 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

todo: specifically, x != 0 mod BLS_MODULUS.

* @see https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md#bls_modular_inverse
*/
bls_modular_inverse : BlsFieldElement -> BlsFieldElement
bls_modular_inverse x = pow`{BlsFieldSize} x NEGATIVE_ONE BLS_MODULUS

/**
* Divide two field elements: x by y
* @see https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md#div
*/
bls_div : BlsFieldElement -> BlsFieldElement -> BlsFieldElement
bls_div x y = (x * (bls_modular_inverse y)) % BLS_MODULUS
Copy link
Collaborator

Choose a reason for hiding this comment

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

todo: I'm worried about overflow here, too.

Here's an implementation of mod mul in cryptol specs, that uses an extension like I mentioned to do safe multiplication and mod.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you're running into this because of a language difference between Python's happily expandable integers and Cryptol's extremely fixed-width ones, so there will be some discrepancy between the spec and your implementation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, you are 💯% correct. I'll fix these.


/*
* ===============
* Unit test suite
* ===============
*/

/**
* Unit tests for `bls_modular_inverse`.
* ```repl
* :prove test_bls_modular_inverse 1 1
* :prove test_bls_modular_inverse 2 0
* :prove test_bls_modular_inverse 3 0x36bd0357810d2d627770d2a2a108d2a556ed06a7aaac4eabaaaaaaabaaaaaaaa
* ```
* NOTE: we just chose the last value at "random"
*/
test_bls_modular_inverse : BlsFieldElement -> BlsFieldElement -> Bit
property test_bls_modular_inverse x expectedY =
bls_modular_inverse x == expectedY

/**
* Unit tests for `bls_modular_inverse`.
* ```repl
* :prove test_bls_div 1 2 0
* :prove test_bls_div 13 1 13
* :prove test_bls_div 57 13 0x15eaf636af000c906a5000958036c58484dfe5d59d8b7c9e89d89d8ad89d89dc
* ```
* NOTE: we just chose the last value at "random"
*/
test_bls_div : BlsFieldElement -> BlsFieldElement -> BlsFieldElement -> Bit
property test_bls_div x y expected =
bls_div x y == expected