UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

170 lines (169 loc) 7.6 kB
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;