Alt_BN128 Syscalls - Simplified Error Code
Summary
Simplify the return error code for the family of Alt_BN128 syscalls:
sol_alt_bn128_group_op
, sol_alt_bn128_compression
and sol_poseidon
.
A single error code is sufficient, in line with all other syscalls.
Motivation
Syscalls in Solana can return:
- Success, e.g. represented in Rust as
Ok(0)
orOk(SUCCESS)
- Error to the program, e.g. represented in Rust as
Ok(1)
- Fatal error to the VM, aborting the transaction, e.g. represented in Rust
as
Err(<something>)
Most syscalls only have a single error code returned to the program, i.e. Ok(1)
.
The family of Alt_BN128 syscalls, vice versa, has a richer set of error codes.
This proposal aims to simplify the error value for these syscalls, in line with
all the other syscalls, and simply return Ok(1)
(in addition to fatal errors,
that are left unchanged).
We stress that multiple error codes cause a maintenance burden for the validators. Moreover, if two different implementation were to return different error codes, an attacker could exploit the different behavior to cause consensus failure.
Alternatives Considered
Leave as is.
New Terminology
n/a
Detailed Design
Syscall sol_alt_bn128_group_op
The syscall sol_alt_bn128_group_op
computes operations on the Alt_BN128 curve, including point addition
in G1, scalar multiplication in G1, and pairing.
The syscall accepts the following inputs:
-
group_op
: the operation to perform:0
: point add in G11
: (reserved for) point sub in G12
: scalar multiplication in G13
: pairing
-
input
: the serialized inputs to the operation.
Notes:
- Input and output depend on the operation. In all cases they are serialized in standard big endian format.
- Points and scalars must be validated.
- Point sub in G1 is not implemented. The
group_op
value1
is reserved.
Point add in G1
Inputs: 2 points in G1.
Output: 1 point in G1.
Scalar multiplication in G1
Inputs: 1 point in G1, 1 scalar.
Output: 1 point in G1.
Pairing
Inputs: 1 point in G1, 1 point in G2
Output: 1
if the pairing is 1, 0
otherwise.
The output is serialized as a 256-bit big integer.
Fatal Errors.
- Validate
group_op
is0
,2
, or3
(known operation). - Compute units
- Memory mapping for input/output
Error Code(s).
Any error caused while computing the operation
is returned as error code 1
, i.e. Ok(1)
in Rust.
This includes validating that the input has the valid length, the input points and scalars are valid, and the operation is successful.
Syscall sol_alt_bn128_compression
The syscall sol_alt_bn128_compression
allows to compress or decompress points in G1 or G2 groups over the Alt_BN128
curve.
The syscall accepts the following inputs:
-
op
: the operation to perform:0
: G1 compress1
: G1 decompress2
: G2 compress3
: G2 decompress
-
input
: the input point to compress / decompress, serialized in standard big endian format.
The output is a point, serialized in standard big endian format.
Note: for performance reasons, this syscall does NOT validate whether the
input is actually an element of G1 or G2.
The intent is to use this syscall in combination with sol_alt_bn128_group_op
,
that performs validation, and therefore not duplicate the expensive check.
Fatal Errors.
- Validate
op
is0
,1
,2
, or3
(known operation). - Compute units
- Memory mapping for input/output
Error Code(s).
Any error caused while computing the compress or decompress operation
is returned as error code 1
, i.e. Ok(1)
in Rust.
This includes validating that the input has the valid length, and decompression is successful.
Syscall sol_poseidon
The syscall sol_poseidon
computes the Poseidon hash on an array of input values.
The syscall accepts the following inputs:
parameters
:0
to represent the choice of the Alt_BN128 curve.endianness
:0
for big endian input/output,1
for little endian.vals_len
: number of input values to hash. Max supported 12 values.vals
: the input values to hash. In line with other hash syscalls, this is an array of buffers. For Poseidon, each buffer represents an element in the curve scalar field, encoded as 32 bytes, with the specified endianness.
The output is an element of the curve scalar field, encoded as 32 bytes, with the specified endianness.
Fatal Errors.
- Validate
parameters
is0
(known curve). - Validate
endianness
is0
or1
(known endianness). - Validate
vals_len
is less or equal to 12. - Compute units
- Memory mapping for input/output
Error Code(s).
Any error caused while computing the Poseidon hash function is returned
as error code 1
, i.e. Ok(1)
in Rust.
This includes validating that the input buffers are valid field elements, and other errors that may occur while calculating the Poseidon hash.
Impact
Implementing the error logic inside validators will be much easier and less error prone.
Dapp developers will have less fine-grained errors, but this is in line with all the other syscalls.
Security Considerations
Simplifying to one single error code reduces the risk of two different validator implementations returining different error codes, which could be exploited to cause a consensus failure.
This change will also hide some internal implementation details, for example
the err code TryIntoVecError
, which is a plus from a security perspective.
The implementation should be straightforward: change the return from Ok(err_num)
to Ok(1)
, so low risk.
Backwards Compatibility
The syscall sol_alt_bn128_group_op
is enabled in testnet, therefore we'll
feature gate the change. Programs using this syscall may need to adapt to the
simplified error code, but this isn't expected to be an issue in practice.
For simplicity, we'll keep the change to all 3 syscalls under the same feature gate.