Point Doubling (P -> 2P) Secp256k1 椭圆曲线的基点

Point Doubling (P -> 2P) The Base Point of the Secp256k1 Elliptic Curve

作为学习练习,我正在尝试为 Secp256k1 椭圆曲线编写第一个点加倍(基点 P -> 2P)的代码。我正在使用 Javascript 和 BigNumber 的 ethers 包。令人沮丧的是,我 运行 遇到了一个问题,我得到的 2P 的结果似乎不在曲线上。有人可以帮我确定我在哪里犯了错误吗?

我得到的坐标是:

X: 0xf1b9e9c77c87bf0ac622382b581826898cfc9232e025d86d904bfd33375faf1a
Y: 0x8162c7b446b54638e9181b71770b2d718e6953a360625a02392097c7db09c608

我的 isPointOnCurve() 方法 returns 错误。作为健全性检查,我检查了 isPointOnCurve() 方法中的基点,结果 returns 为真(谢天谢地)。

请看下面我的代码:

const { ethers, BigNumber } = require('ethers');

//variable initialization found from https://en.bitcoin.it/wiki/Secp256k1
bigZero = BigNumber.from(0);
bigTwo = BigNumber.from(2);
bigThree = BigNumber.from(3);
ellipticCurveB = BigNumber.from(7);
generatorPrime = BigNumber.from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
order = BigNumber.from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
baseXCoord = BigNumber.from("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798");
baseYCoord = BigNumber.from("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");

// slope = ( (3*x^2) * (2*y)^-1 ) mod order
// 2Px = slope^2 - 2*baseXCoord
// 2Py = slope * ( 2Px - baseXCoord ) - baseYCoord

m = (bigThree.mul(baseXCoord.pow(bigTwo)).mul(modinv(bigTwo.mul(baseYCoord), order))).mod(order);
TwoPx = (m.pow(bigTwo).sub(bigTwo.mul(baseXCoord))).mod(order);
TwoPy = ((m.mul(baseXCoord.sub(TwoPx))).sub(baseYCoord)).mod(order);

console.log(TwoPx);
console.log(TwoPy);
console.log(isPointOnCurve(TwoPx, TwoPy));

// Helper Functions:
// Check if point is on Curve, Calculate extended GCD, modular inverse

function isPointOnCurve(x,y){
    b = ellipticCurveB;
    p = generatorPrime;
    rem = (y.pow(bigTwo).sub(x.pow(bigThree)).sub(b)).mod(p);
    return rem.eq(bigZero);
}

function egcd(a, b) {
    var s = BigNumber.from(0), t = BigNumber.from(1), u = BigNumber.from(1), v = BigNumber.from(0);
    while (!a.eq(BigNumber.from(0))) {
        var q = b.div(a) | BigNumber.from(0), r = b.mod(a);
        var m = s.sub(u.mul(q)), n = t.sub(v.mul(q));
        b = a;
        a = r;
        s = u;
        t = v;
        u = m;
        v = n;
    }
    return [b, s, t];
}

function mod(x, y) {
    return (x.mod(y).add(y)).mod(y);
}

function modinv(x, y) {
    var tuple = egcd(x.mod(y), y);
    if (!tuple[0].eq(BigNumber.from(1))) {
        return null;
    }
    return mod(tuple[1], y);
}

正如 kelalaka 在对原文 post 的评论中指出的那样,我混淆了群的阶和有限域 Fp。当我本应使用用于定义有限域的素数 p 模值时,我得到的是对群阶取模的值。

我得到的新的正确结果是:

X: 0xc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5
Y: 0x1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a

如果有人想使用此代码,我已将其更新为正确的,并对其进行了清理以使其更具可读性:

bigZero = BigNumber.from(0);
bigTwo = BigNumber.from(2);
bigThree = BigNumber.from(3);
ellipticCurveB = BigNumber.from(7);
generatorPrime =     BigNumber.from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
baseXCoord = BigNumber.from("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798");
baseYCoord = BigNumber.from("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");

// slope = ( (3*x^2) * (2*y)^-1 ) mod order
threeXSquared = bigThree.mul(baseXCoord.pow(bigTwo));
modInv2y = modinv(bigTwo.mul(baseYCoord), generatorPrime);
m = threeXSquared.mul(modInv2y).mod(generatorPrime);

// 2Px = slope^2 - 2*baseXCoord
mSquared = m.pow(bigTwo);
twoXbase = bigTwo.mul(baseXCoord);
TwoPx = (mSquared.sub(twoXbase)).mod(generatorPrime);

// 2Py = slope * ( 2Px - baseXCoord ) - baseYCoord
pointSlopeX = m.mul(baseXCoord.sub(TwoPx)); 
TwoPy = (pointSlopeX).sub(baseYCoord).mod(generatorPrime);

console.log(TwoPx);
console.log(TwoPy);
console.log(isPointOnCurve(TwoPx, TwoPy));

// Helper Functions:
// Check if point is on Curve, Calculate extended GCD, modular inverse

function isPointOnCurve(x,y){
    b = ellipticCurveB;
    p = generatorPrime;
    rem = (y.pow(bigTwo).sub(x.pow(bigThree)).sub(b)).mod(p);
    return rem.eq(bigZero);
}

function egcd(a, b) {
    var s = BigNumber.from(0), t = BigNumber.from(1), u = BigNumber.from(1), v = BigNumber.from(0);
    while (!a.eq(BigNumber.from(0))) {
        var q = b.div(a) | BigNumber.from(0), r = b.mod(a);
        var m = s.sub(u.mul(q)), n = t.sub(v.mul(q));
        b = a;
        a = r;
        s = u;
        t = v;
        u = m;
        v = n;
    }
    return [b, s, t];
}

function modulus(x, y) {
    return (x.mod(y).add(y)).mod(y);
}

function modinv(x, y) {
    var tuple = egcd(x.mod(y), y);
    if (!tuple[0].eq(BigNumber.from(1))) {
        return null;
    }
    return modulus(tuple[1], y);
}