Skip to content

Commit

Permalink
ec math for bls12-381 and bn254, including specs
Browse files Browse the repository at this point in the history
Moved benchmarks into pairing_test and improved them

Removed the restriction of using 32 byte scalars, but but with a 32
byte _maximum_, so that costs can be calculated with that assumption.
  • Loading branch information
jannotti committed Mar 7, 2023
1 parent 32219d6 commit c98d988
Show file tree
Hide file tree
Showing 14 changed files with 1,460 additions and 592 deletions.
2 changes: 1 addition & 1 deletion cmd/opdoc/opdoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"github.com/algorand/go-algorand/protocol"
)

var docVersion = 8
var docVersion = 9

func opGroupMarkdownTable(names []string, out io.Writer) {
fmt.Fprint(out, `| Opcode | Description |
Expand Down
6 changes: 6 additions & 0 deletions data/transactions/logic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@ return stack matches the name of the input value.
| `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key |
| `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y |
| `vrf_verify s` | Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. |
| `ec_add g` | for curve points A and B, return the curve point A + B |
| `ec_scalar_mul g` | for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. |
| `ec_pairing_check g` | 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 |
| `ec_multi_exp g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn |
| `ec_subgroup_check g` | 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. |
| `ec_map_to g` | maps field element A to group G |
| `+` | A plus B. Fail on overflow. |
| `-` | A minus B. Fail if B > A. |
| `/` | A divided by B (truncated division). Fail if B == 0. |
Expand Down
79 changes: 79 additions & 0 deletions data/transactions/logic/TEAL_opcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1560,3 +1560,82 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo
| 0 | BlkSeed | []byte | |
| 1 | BlkTimestamp | uint64 | |


## ec_add g

- Opcode: 0xe0 {uint8 curve}
- Stack: ..., A: []byte, B: []byte → ..., []byte
- for curve points A and B, return the curve point A + B
- **Cost**: BN254g1=310 BN254g2=430 BLS12_381g1=540 BLS12_381g2=750
- Availability: v9

`EC` Groups:

| Index | Name | Notes |
| - | ------ | --------- |
| 0 | BN254g1 | G1 of the BN254 curve. Points encoded as 32 byte X following by 32 byte Y |
| 1 | BN254g2 | G2 of the BN254 curve. Points encoded as 64 byte X following by 64 byte Y |
| 2 | BLS12_381g1 | G1 of the BLS 12-381 curve. Points encoded as 48 byte X following by 48 byte Y |
| 3 | BLS12_381g2 | G2 of the BLS 12-381 curve. Points encoded as 96 byte X following by 48 byte Y |


A and B are curve points in affine representation: field element X concatenated with field element Y. Field element `Z` is encoded as follows.
For the base field elements (Fp), `Z` is encoded as a big-endian number and must be lower than the field modulus.
For the quadratic field extension (Fp2), `Z` is encoded as the concatenation of the individual encoding of the coefficients. For an Fp2 element of the form `Z = Z0 + Z1 i`, where `i` is a formal quadratic non-residue, the encoding of Z is the concatenation of the encoding of `Z0` and `Z1` in this order. (`Z0` and `Z1` must be less than the field modulus).

The point at infinity is encoded as `(X,Y) = (0,0)`.
Groups G1 and G2 are denoted additively.

Fails if A or B is not in G.
A and/or B are allowed to be the point at infinity.
Does _not_ check if A and B are in the main prime-order subgroup.

## ec_scalar_mul g

- Opcode: 0xe1 {uint8 curve}
- Stack: ..., A: []byte, B: []byte → ..., []byte
- for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B.
- **Cost**: BN254g1=2200 BN254g2=4460 BLS12_381g1=3640 BLS12_381g2=8530
- Availability: v9

A is a curve point encoded and checked as described in `ec_add`. Scalar B is interpreted as a big-endian unsigned integer. Fails if B exceeds 32 bytes.

## ec_pairing_check g

- Opcode: 0xe2 {uint8 curve}
- Stack: ..., A: []byte, B: []byte → ..., uint64
- 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0
- **Cost**: BN254g1=18000 BN254g2=18000 BLS12_381g1=15000 BLS12_381g2=15000
- Availability: v9

A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes.

## ec_multi_exp g

- Opcode: 0xe3 {uint8 curve}
- Stack: ..., A: []byte, B: []byte → ..., []byte
- for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn
- **Cost**: BN254g1=800 BN254g2=1800 BLS12_381g1=1400 BLS12_381g2=3500
- Availability: v9

A is a list of concatenated points, encoded and checked as described in `ec_add`. B is a list of concatenated scalars which, unlike ec_scalar_mul, must all be exactly 32 bytes long.
The name `ec_multi_exp` was chosen to reflect common usage, but a more consistent name would be `ec_multi_scalar_mul`

## ec_subgroup_check g

- Opcode: 0xe4 {uint8 curve}
- Stack: ..., A: []byte → ..., uint64
- 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all.
- **Cost**: BN254g1=50 BN254g2=11500 BLS12_381g1=5600 BLS12_381g2=7100
- Availability: v9

## ec_map_to g

- Opcode: 0xe5 {uint8 curve}
- Stack: ..., A: []byte → ..., []byte
- maps field element A to group G
- **Cost**: BN254g1=1700 BN254g2=11000 BLS12_381g1=5600 BLS12_381g2=43000
- Availability: v9

BN254 points are mapped by the SVDW map. BLS12-381 points are mapped by the SSWU map.
G1 element inputs are base field elements and G2 element inputs are quadratic field elements, with nearly the same encoding rules (for field elements) as defined in `ec_add`. There is one difference of encoding rule: G1 element inputs do not need to be 0-padded if they fit in less than 32 bytes for BN254 and less than 48 bytes for BLS12-381. (As usual, the empty byte array represents 0.) G2 elements inputs need to be always have the required size.
Loading

0 comments on commit c98d988

Please sign in to comment.