o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
170 lines (169 loc) • 7.6 kB
TypeScript
import { CurveParams } from '../../../bindings/crypto/elliptic-curve.js';
import { ProvablePureExtended } from '../types/struct.js';
import { FlexiblePoint, ForeignCurve } from './foreign-curve.js';
import { AlmostForeignField } from '../foreign-field.js';
import { Field3 } from '../gadgets/foreign-field.js';
import { Bytes } from '../wrapped-classes.js';
import type { Bool } from '../bool.js';
export { createEcdsa, EcdsaSignature };
type FlexibleSignature = EcdsaSignature | {
r: AlmostForeignField | Field3 | bigint | number;
s: AlmostForeignField | Field3 | bigint | number;
};
declare class EcdsaSignature {
r: AlmostForeignField;
s: AlmostForeignField;
/**
* Create a new {@link EcdsaSignature} from an object containing the scalars r and s.
*
* 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.
*/
constructor(signature: {
r: AlmostForeignField | Field3 | bigint | number;
s: AlmostForeignField | Field3 | bigint | number;
});
/**
* Coerce the input to a {@link EcdsaSignature}.
*/
static from(signature: FlexibleSignature): EcdsaSignature;
/**
* Create an {@link EcdsaSignature} from a raw 130-char hex string as used in
* [Ethereum transactions](https://ethereum.org/en/developers/docs/transactions/#typed-transaction-envelope).
*/
static fromHex(rawSignature: string): EcdsaSignature;
/**
* Convert this signature to an object with bigint fields.
*/
toBigInt(): {
r: bigint;
s: bigint;
};
/**
* Verify the ECDSA signature given the message (an array of bytes) and public key (a {@link Curve} point).
*
* **Important:** This method returns a {@link Bool} which indicates whether the signature is valid.
* So, to actually prove validity of a signature, you need to assert that the result is true.
*
* @throws if one of the signature scalars is zero or if the public key is not on the curve.
*
* @example
* ```ts
* // create classes for your curve
* class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
* class Scalar extends Secp256k1.Scalar {}
* class Ecdsa extends createEcdsa(Secp256k1) {}
*
* let message = 'my message';
* let messageBytes = new TextEncoder().encode(message);
*
* // outside provable code: create inputs
* let privateKey = Scalar.random();
* let publicKey = Secp256k1.generator.scale(privateKey);
* let signature = Ecdsa.sign(messageBytes, privateKey.toBigInt());
*
* // ...
* // in provable code: create input witnesses (or use method inputs, or constants)
* let pk = Provable.witness(Secp256k1, () => publicKey);
* let msg = Provable.witness(Provable.Array(Field, 9), () => messageBytes.map(Field));
* let sig = Provable.witness(Ecdsa, () => signature);
*
* // verify signature
* let isValid = sig.verify(msg, pk);
* isValid.assertTrue('signature verifies');
* ```
*/
verify(message: Bytes, publicKey: FlexiblePoint): Bool;
/**
* Verify an ECDSA signature generated by the ethers.js library, given the message (as a byte array) and a public key (a {@link Curve} point).
* The message digest used for signing follows the format defined in EIP-191, with the Ethereum-specific prefix.
*
* **Important:** This method returns a {@link Bool} which indicates whether the signature is valid.
* So, to actually prove validity of a signature, you need to assert that the result is true.
*
* **Note:** This method is specifically designed to verify signatures generated by ethers.js.
* Ensure that the curve being used is Secp256k1, as demonstrated in the example.
*
* @throws An error will be thrown if one of the signature scalars is zero or if the public key does not lie on the curve.
*
* @example
* ```ts
* import { Wallet } from 'ethers';
*
* // create the class for Secp256k1 curve
* class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
* class Ecdsa extends createEcdsa(Secp256k1) {}
*
* // outside provable code: create inputs
* let message = 'my message';
* let signatureRaw = await wallet.signMessage(message);
* let compressedPublicKey = wallet.signingKey.compressedPublicKey;
*
* // this also works for uncompressed public keys (wallet.signingKey.publicKey)
* let publicKey = Secp256k1.fromEthers(compressedPublicKey.slice(2));
* let signature = Ecdsa.fromHex(signatureRaw);
*
* // ...
* // in provable code: create input witnesses (or use method inputs, or constants)
* // and verify the signature
* let isValid = signature.verifyEthers(Bytes.fromString(message), publicKey);
* isValid.assertTrue('signature verifies');
* ```
*
* @param message - The original message as a byte array.
* @param publicKey - The public key as a point on the Secp256k1 elliptic curve.
* @returns - A {@link Bool} indicating the validity of the signature.
*/
verifyEthers(message: Bytes, publicKey: FlexiblePoint): Bool;
/**
* Verify the ECDSA signature given the message hash (a {@link Scalar}) and public key (a {@link Curve} point).
*
* This is a building block of {@link EcdsaSignature.verify}, where the input message is also hashed.
* In contrast, this method just takes the message hash (a curve scalar, or the output bytes of a hash function)
* as input, giving you flexibility in choosing the hashing algorithm.
*/
verifySignedHash(msgHash: AlmostForeignField | bigint | Bytes, publicKey: FlexiblePoint): Bool;
/**
* Create an {@link EcdsaSignature} by signing a message with a private key.
*
* Note: This method is not provable, and only takes JS bigints as input.
*/
static sign(message: (bigint | number)[] | Uint8Array, privateKey: bigint): EcdsaSignature;
/**
* Create an {@link EcdsaSignature} by signing a message hash with a private key.
*
* This is a building block of {@link EcdsaSignature.sign}, where the input message is also hashed.
* In contrast, this method just takes the message hash (a curve scalar, or the output bytes of a hash function)
* as input, giving you flexibility in choosing the hashing algorithm.
*
* Note: This method is not provable, and only takes JS bigints or constant Bytes as input.
*/
static signHash(msgHash: bigint | Bytes, privateKey: bigint): EcdsaSignature;
static check(signature: EcdsaSignature): void;
get Constructor(): typeof EcdsaSignature;
static _Curve?: typeof ForeignCurve;
static _provable?: ProvablePureExtended<EcdsaSignature, {
r: bigint;
s: bigint;
}, {
r: string;
s: string;
}>;
/**
* The {@link ForeignCurve} on which the ECDSA signature is defined.
*/
static get Curve(): typeof ForeignCurve;
/**
* `Provable<EcdsaSignature>`
*/
static get provable(): ProvablePureExtended<EcdsaSignature, {
r: bigint;
s: bigint;
}, {
r: string;
s: string;
}>;
}
/**
* Create a class {@link EcdsaSignature} for verifying ECDSA signatures on the given curve.
*/
declare function createEcdsa(curve: CurveParams | typeof ForeignCurve): typeof EcdsaSignature;