Reserved IP Address°C
04-28-2025

Failed to fetch data

Getting your Trinity Audio player ready...

This post was first published on Medium.

We have implemented ECDSA signature verification algorithm in Script. It can verify if an arbitrary message is signed by a private key corresponding to a given public key, while OP_CHECKSIG can only verify signatures when the message is the current spending transaction¹. Surprisingly, this is done without introducing any new opcode such as OP_DATASIGVERIFY (aka, OP_CHECKDATASIG) on BCH.

Elliptic Curve Digital Signature Algorithm (ECDSA)

ECDSA is the algorithm used in Bitcoin for signature generation and verification. The verification algorithm is listed below.

ECDSA Signature Verification

Implementation

We have implemented the algorithm as shown below, using the elliptic curve library we released before.

First, we need to extract r and s components from the signature, which is encoded in DER format. Since they are big-endian, we have to convert to little-endian, which is how data is encoded in Script/sCrypt.

DER

After r and s are retrieved, we simply run the standard ECDSA verification algorithm.

import "ec.scrypt";
import "util.scrypt";
struct RSPair {
int r;
int s;
}
// ECDSA signatures verification for secp256k1, for arbitrary message @msg
contract ECDSA {
public function verify(Sig sig, PubKey pubKey, bytes msg,
int invS, Point P, int lambda, Point U1, PointMulAux u1Aux, Point U2, PointMulAux u2Aux) {
// extract (r, s) from sig
RSPair rs = parseDERSig(sig);
int r = rs.r;
int s = rs.s;
// within range
require(r >= 1 && r < EC.n);
require(s >= 1 && s < EC.n);
// verify invS
require((s * invS) % EC.n == 1);
int e = unpack(sha256(msg));
int u1 = (e * invS) % EC.n;
int u2 = (r * invS) % EC.n;
// U1 = u1 * G
require(EC.isMul(EC.G, u1, U1, u1Aux));
Point Q = pubKey2Point(pubKey);
// U2 = u2 * Q
require(EC.isMul(Q, u2, U2, u2Aux));
// P == U1 + U2
require(EC.isSum(U1, U2, lambda, P));
// cannot be identify
require(P != EC.ZERO);
require((P.x - r) % EC.n == 0);
}
// parse signature in DER format to get (r, s) pair
static function parseDERSig(Sig sig) : RSPair {
int rLen = unpack(sig[3 : 4]);
int r = fromBESigned(sig[4 : 4 + rLen]);
int sLen = unpack(sig[6 + rLen : 7 + rLen]);
int s = fromBESigned(sig[7 + rLen : 7 + rLen + sLen]);
return { r , s };
}
// r & s are signed big endian
static function fromBESigned(bytes b) : int {
// convert big-endian to little-endian: either 32 or 33 bytes
bytes bLE = len(b) == 32 ? reverseBytes(b, 32) : reverseBytes(b, 33);
return unpack(bLE);
}
// convert public key to a point, assuming it's uncompressed
static function pubKey2Point(PubKey pubKey) : Point {
require(pubKey[: 1] == b'04');
return { unpack(pubKey[1 : 33]), unpack(pubKey[33 : 65]) };
}
}
view raw ecdsa.js hosted with ❤ by GitHub

ECDSA Contract

***

NOTE:

[1] More precisely, it verifies signature against sighash.

Recommended for you

India’s quantum leap poses national security risks: NITI Aayog
NITI Aayog's report said that quantum techs would usher in next-generation advancements in defense and assess its impact on national...
April 24, 2025
India launches first full-stack quantum computing system
During World Quantum Day, India unveiled its first full-stack quantum computing system, positioning itself at the forefront of tech revolution.
April 23, 2025
Advertisement
Advertisement
Advertisement