【问题标题】:Point Doubling (P -> 2P) The Base Point of the Secp256k1 Elliptic Curve点倍增 (P -> 2P) Secp256k1 椭圆曲线的基点
【发布时间】:2021-08-05 15:43:36
【问题描述】:

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

我得到的坐标是:

X: 0xf1b9e9c77c87bf0ac622382b581826898cfc9232e025d86d904bfd33375faf1a
Y: 0x8162c7b446b54638e9181b71770b2d718e6953a360625a02392097c7db09c608

从我的 isPointOnCurve() 方法返回 false。作为健全性检查,我检查了 isPointOnCurve() 方法中的基点,结果返回 true(谢天谢地)。

请看我下面的代码:

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);
}

【问题讨论】:

  • 您混淆了组的顺序和定义曲线的字段。曲线坐标定义在 F_p where p=FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F 所以你需要找到逆并根据这个模数执行坐标的模归约。
  • @kelalaka 所以我进入了我的代码并将模数更改为 p(我称之为 primeGenerator),它起作用了!谢谢!我会马上去更新帖子。不过,我肯定很困惑。除了确定合法私钥的范围之外,组顺序还有什么用?计算中的任何内容?
  • 组顺序对于discrete log 很重要。考虑 [a]G 和 [b]G 是在 DHKE 期间通过的对,并且双方都计算 [ab]G。 ([2]G 是翻倍,[3]G 是三倍,等等。)那么如果攻击者可以解决 Dlog 而不是繁荣!
  • 您可以发布您的更新代码作为答案,至少我会投票。并使其更具可读性 m、twoPx 和 twoPy 并不是很容易掌握,使用中间变量...
  • @kelalaka 非常感谢!你帮了我很大的忙,我学到的东西比我预期的要多得多。考虑到您的 cmets,我已经发布了我的答案。

标签: javascript cryptography ethereum bitcoin elliptic-curve


【解决方案1】:

正如 kelalaka 在对原始帖子的评论中指出的那样,我混淆了组的顺序和有限域 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);
}

【讨论】:

  • 您认为代码更具可读性和可管理性。这应该是考虑性能/安全性之前的第一步。玩得开心!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2015-05-09
相关资源
最近更新 更多