o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
366 lines (365 loc) • 15.2 kB
TypeScript
import { CurveParams, CurveAffine } from '../../../bindings/crypto/elliptic-curve.js';
import { ProvablePureExtended } from '../types/struct.js';
import { AlmostForeignField } from '../foreign-field.js';
import { Point } from '../gadgets/elliptic-curve.js';
import { Field3 } from '../gadgets/foreign-field.js';
export { createForeignCurve, ForeignCurve };
export { toPoint, FlexiblePoint, ForeignCurveNotNeeded };
type FlexiblePoint = {
x: AlmostForeignField | Field3 | bigint | number;
y: AlmostForeignField | Field3 | bigint | number;
};
declare function toPoint({ x, y }: ForeignCurve): Point;
declare class ForeignCurve {
x: AlmostForeignField;
y: AlmostForeignField;
/**
* Create a new {@link ForeignCurve} from an object representing the (affine) x and y coordinates.
*
* Note: Inputs must be range checked if they originate from a different field with a different modulus or if they are not constants. Please refer to the {@link ForeignField} constructor comments for more details.
*
* @example
* ```ts
* let x = new ForeignCurve({ x: 1n, y: 1n });
* ```
*
* **Important**: By design, there is no way for a `ForeignCurve` to represent the zero point.
*
* **Warning**: This fails for a constant input which does not represent an actual point on the curve.
*/
constructor(g: {
x: AlmostForeignField | Field3 | bigint | number;
y: AlmostForeignField | Field3 | bigint | number;
});
/**
* Coerce the input to a {@link ForeignCurve}.
*/
static from(g: ForeignCurve | FlexiblePoint): ForeignCurve;
/**
* Parses a hexadecimal string representing an uncompressed elliptic curve point and coerces it into a {@link ForeignCurve} point.
*
* The method extracts the x and y coordinates from the provided hex string and verifies that the resulting point lies on the curve.
*
* **Note:** This method only supports uncompressed elliptic curve points, which are 65 bytes in total (1-byte prefix + 32 bytes for x + 32 bytes for y).
*
* @param hex - The hexadecimal string representing the uncompressed elliptic curve point.
* @returns - A point on the foreign curve, parsed from the given hexadecimal string.
*
* @throws - Throws an error if the input is not a valid public key.
*
* @example
* ```ts
* class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
*
* const publicKeyHex = '04f8b8db25c619d0c66b2dc9e97ecbafafae...'; // Example hex string for uncompressed point
* const point = Secp256k1.fromHex(publicKeyHex);
* ```
*
* **Important:** This method is only designed to handle uncompressed elliptic curve points in hex format.
*/
static fromHex(hex: string): ForeignCurve;
/**
* Create a new {@link ForeignCurve} instance from an Ethereum public key in hex format, which may be either compressed or uncompressed.
* This method is designed to handle the parsing of public keys as used by the ethers.js library.
*
* The input should represent the affine x and y coordinates of the point, in hexadecimal format.
* Compressed keys are 33 bytes long and begin with 0x02 or 0x03, while uncompressed keys are 65 bytes long and begin with 0x04.
*
* **Warning:** This method is specifically designed for use with the Secp256k1 curve. Using it with other curves may result in incorrect behavior or errors.
* Ensure that the curve setup matches Secp256k1, as shown in the example, to avoid unintended issues.
*
* @example
* ```ts
* import { Wallet, Signature, getBytes } from 'ethers';
*
* class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
*
* const wallet = Wallet.createRandom();
*
* const publicKey = Secp256k1.fromEthers(wallet.publicKey.slice(2));
* ```
*
* @param hex - The public key as a hexadecimal string (without the "0x" prefix).
* @returns A new instance of the curve representing the given public key.
*/
static fromEthers(hex: string): ForeignCurve;
/**
* The constant generator point.
*/
static get generator(): ForeignCurve;
/**
* The size of the curve's base field.
*/
static get modulus(): bigint;
/**
* The size of the curve's base field.
*/
get modulus(): bigint;
/**
* @internal
* Checks whether this curve point is constant.
*
* See {@link FieldVar} to understand constants vs variables.
*/
isConstant(): boolean;
/**
* Convert this curve point to a point with bigint coordinates.
*/
toBigint(): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
/**
* Elliptic curve addition.
*
* ```ts
* let r = p.add(q); // r = p + q
* ```
*
* **Important**: this is _incomplete addition_ and does not handle the degenerate cases:
* - Inputs are equal, `g = h` (where you would use {@link double}).
* In this case, the result of this method is garbage and can be manipulated arbitrarily by a malicious prover.
* - Inputs are inverses of each other, `g = -h`, so that the result would be the zero point.
* In this case, the proof fails.
*
* If you want guaranteed soundness regardless of the input, use {@link addSafe} instead.
*
* @throws if the inputs are inverses of each other.
*/
add(h: ForeignCurve | FlexiblePoint): ForeignCurve;
/**
* Safe elliptic curve addition.
*
* This is the same as {@link add}, but additionally proves that the inputs are not equal.
* Therefore, the method is guaranteed to either fail or return a valid addition result.
*
* **Beware**: this is more expensive than {@link add}, and is still incomplete in that
* it does not succeed on equal or inverse inputs.
*
* @throws if the inputs are equal or inverses of each other.
*/
addSafe(h: ForeignCurve | FlexiblePoint): ForeignCurve;
/**
* Elliptic curve doubling.
*
* @example
* ```ts
* let r = p.double(); // r = 2 * p
* ```
*/
double(): ForeignCurve;
/**
* Elliptic curve negation.
*
* @example
* ```ts
* let r = p.negate(); // r = -p
* ```
*/
negate(): ForeignCurve;
/**
* Elliptic curve scalar multiplication, where the scalar is represented as a {@link ForeignField} element.
*
* **Important**: this proves that the result of the scalar multiplication is not the zero point.
*
* @throws if the scalar multiplication results in the zero point; for example, if the scalar is zero.
*
* @example
* ```ts
* let r = p.scale(s); // r = s * p
* ```
*/
scale(scalar: AlmostForeignField | bigint | number): ForeignCurve;
static assertOnCurve(g: ForeignCurve): void;
/**
* Assert that this point lies on the elliptic curve, which means it satisfies the equation
* `y^2 = x^3 + ax + b`
*/
assertOnCurve(): void;
static assertInSubgroup(g: ForeignCurve): void;
/**
* Assert that this point lies in the subgroup defined by `order*P = 0`.
*
* Note: this is a no-op if the curve has cofactor equal to 1. Otherwise
* it performs the full scalar multiplication `order*P` and is expensive.
*/
assertInSubgroup(): void;
/**
* Check that this is a valid element of the target subgroup of the curve:
* - Check that the coordinates are valid field elements
* - Use {@link assertOnCurve()} to check that the point lies on the curve
* - If the curve has cofactor unequal to 1, use {@link assertInSubgroup()}.
*/
static check(g: ForeignCurveNotNeeded): void;
get Constructor(): typeof ForeignCurve;
static _Bigint?: CurveAffine;
static _Field?: typeof AlmostForeignField;
static _Scalar?: typeof AlmostForeignField;
static _provable?: ProvablePureExtended<ForeignCurve, {
x: bigint;
y: bigint;
}, {
x: string;
y: string;
}>;
/**
* Curve arithmetic on JS bigints.
*/
static get Bigint(): {
name: string;
Field: {
modulus: bigint;
sizeInBits: number;
t: bigint;
M: bigint;
twoadicRoot: bigint;
mod(x: bigint): bigint;
add(x: bigint, y: bigint): bigint;
not(x: bigint, bits: number): bigint;
negate(x: bigint): bigint;
sub(x: bigint, y: bigint): bigint;
mul(x: bigint, y: bigint): bigint;
inverse: (x: bigint) => bigint | undefined;
div(x: bigint, y: bigint): bigint | undefined;
square(x: bigint): bigint;
isSquare(x: bigint): boolean;
sqrt(x: bigint): bigint | undefined;
power(x: bigint, n: bigint): bigint;
dot(x: bigint[], y: bigint[]): bigint;
equal(x: bigint, y: bigint): boolean;
isEven(x: bigint): boolean;
random(): bigint;
fromNumber(x: number): bigint;
fromBigint(x: bigint): bigint;
rot(x: bigint, bits: bigint, direction?: "left" | "right", maxBits?: bigint): bigint;
leftShift(x: bigint, bits: number, maxBitSize?: number): bigint;
rightShift(x: bigint, bits: number): bigint;
};
Scalar: {
modulus: bigint;
sizeInBits: number;
t: bigint;
M: bigint;
twoadicRoot: bigint;
mod(x: bigint): bigint;
add(x: bigint, y: bigint): bigint;
not(x: bigint, bits: number): bigint;
negate(x: bigint): bigint;
sub(x: bigint, y: bigint): bigint;
mul(x: bigint, y: bigint): bigint;
inverse: (x: bigint) => bigint | undefined;
div(x: bigint, y: bigint): bigint | undefined;
square(x: bigint): bigint;
isSquare(x: bigint): boolean;
sqrt(x: bigint): bigint | undefined;
power(x: bigint, n: bigint): bigint;
dot(x: bigint[], y: bigint[]): bigint;
equal(x: bigint, y: bigint): boolean;
isEven(x: bigint): boolean;
random(): bigint;
fromNumber(x: number): bigint;
fromBigint(x: bigint): bigint;
rot(x: bigint, bits: bigint, direction?: "left" | "right", maxBits?: bigint): bigint;
leftShift(x: bigint, bits: number, maxBitSize?: number): bigint;
rightShift(x: bigint, bits: number): bigint;
};
modulus: bigint;
order: bigint;
a: bigint;
b: bigint;
cofactor: bigint | undefined;
hasCofactor: boolean;
zero: {
x: bigint;
y: bigint;
infinity: true;
};
one: {
infinity: boolean;
x: bigint;
y: bigint;
};
hasEndomorphism: boolean;
readonly Endo: {
scalar: bigint;
base: bigint;
decomposeMaxBits: number;
decompose(s: bigint): readonly [{
readonly value: bigint;
readonly isNegative: boolean;
readonly abs: bigint;
}, {
readonly value: bigint;
readonly isNegative: boolean;
readonly abs: bigint;
}];
endomorphism(P: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): {
x: bigint;
y: bigint;
};
scaleProjective(g: import("../../../bindings/crypto/elliptic-curve.js").GroupProjective, s: bigint): {
x: bigint;
y: bigint;
z: bigint;
};
scale(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine, s: bigint): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
};
from(g: {
x: bigint;
y: bigint;
}): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
fromNonzero(g: {
x: bigint;
y: bigint;
}): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
equal(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine, h: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): boolean;
isOnCurve(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): boolean;
isInSubgroup(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): boolean;
add(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine, h: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
double(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
negate(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
sub(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine, h: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
scale(g: import("../../../bindings/crypto/elliptic-curve.js").GroupAffine, s: bigint | boolean[]): import("../../../bindings/crypto/elliptic-curve.js").GroupAffine;
};
/**
* The base field of this curve as a {@link ForeignField}.
*/
static get Field(): typeof AlmostForeignField;
/**
* The scalar field of this curve as a {@link ForeignField}.
*/
static get Scalar(): typeof AlmostForeignField;
/**
* `Provable<ForeignCurve>`
*/
static get provable(): ProvablePureExtended<ForeignCurve, {
x: bigint;
y: bigint;
}, {
x: string;
y: string;
}>;
}
/**
* @see: {@link ForeignCurve}
*/
declare class ForeignCurveNotNeeded extends ForeignCurve {
constructor(g: {
x: AlmostForeignField | Field3 | bigint | number;
y: AlmostForeignField | Field3 | bigint | number;
});
static check(g: ForeignCurveNotNeeded): void;
}
/**
* Create a class representing an elliptic curve group, which is different from the native {@link Group}.
*
* ```ts
* const Curve = createForeignCurve(Crypto.CurveParams.Secp256k1);
* ```
*
* `createForeignCurve(params)` takes curve parameters `CurveParams` as input.
* We support `modulus` and `order` to be prime numbers up to 259 bits.
*
* The returned {@link ForeignCurveNotNeeded} class represents a _non-zero curve point_ and supports standard
* elliptic curve operations like point addition and scalar multiplication.
*
* {@link ForeignCurveNotNeeded} also includes to associated foreign fields: `ForeignCurve.Field` and `ForeignCurve.Scalar`, see {@link createForeignField}.
*/
declare function createForeignCurve(params: CurveParams): typeof ForeignCurve;