使用此椭圆曲线点乘法计算的点不在曲线上,此类带来算术异常

2024-02-03

我得到了使用标准投影坐标进行点乘错误的堆栈。我不知道我错过了什么,但相乘的点并不位于曲线上,有时它会输出类似的内容算术异常:整数不可逆。

public class ECPointArthimetic {

    EllipticCurve ec;
    private BigInteger x;
    private BigInteger y;
    private BigInteger z;
    private BigInteger zinv;
    private BigInteger one = BigInteger.ONE;
    private BigInteger zero = BigInteger.ZERO;
    private boolean infinity;

    public ECPointArthimetic(EllipticCurve ec, BigInteger x, BigInteger y, BigInteger z) {
        this.ec = ec;
        this.x = x;
        this.y = y;

        // Projective coordinates: either zinv == null or z * zinv == 1
        // z and zinv are just BigIntegers, not fieldElements
        if (z == null) {
            this.z = BigInteger.ONE;
        } else {
            this.z = z;
        }
        this.zinv = null;
        infinity = false;
        //TODO: compression flag
    }

    public BigInteger getX() {
        if (this.zinv == null) {
            this.zinv = this.z.modInverse(this.ec.getP());
        }
        return this.x.multiply(this.zinv).mod(this.ec.getP());
    }

    public BigInteger getY() {
        if (this.zinv == null) {
            this.zinv = this.z.modInverse(this.ec.getP());
        }
        return this.y.multiply(this.zinv).mod(this.ec.getP());
    }

    public boolean pointEquals(ECPointArthimetic other) {
        if (other == this) {
            return true;
        }
        if (this.isInfinity()) {
            return other.isInfinity();
        }
        if (other.isInfinity()) {
            return this.isInfinity();
        }
        BigInteger u, v;
        // u = Y2 * Z1 - Y1 * Z2
        u = other.y.multiply(this.z).subtract(this.y.multiply(other.z)).mod(this.ec.getP());
        if (!u.equals(BigInteger.ZERO)) {
            return false;
        }
        // v = X2 * Z1 - X1 * Z2
        v = other.x.multiply(this.z).subtract(this.x.multiply(other.z)).mod(this.ec.getP());
        return v.equals(BigInteger.ZERO);
    }

    public boolean isInfinity() {
        if ((this.x == zero) && (this.y == zero)) {
            return true;
        }
        return this.z.equals(BigInteger.ZERO) && !this.y.equals(BigInteger.ZERO);
    }

    public ECPointArthimetic negate() {
        return new ECPointArthimetic(this.ec, this.x, this.y.negate(), this.z);
    }

    public ECPointArthimetic add(ECPointArthimetic b) {
        if (this.isInfinity()) {
            return b;
        }
        if (b.isInfinity()) {
            return this;
        }
        ECPointArthimetic R = new ECPointArthimetic(this.ec, zero, zero, null);
        // u = Y2 * Z1 - Y1 * Z2
        BigInteger u = b.y.multiply(this.z).
                subtract(this.y.multiply(b.z)).mod(this.ec.getP());
        // v = X2 * Z1 - X1 * Z2
        BigInteger v = b.x.multiply(this.z).
                subtract(this.x.multiply(b.z)).mod(this.ec.getP());

        if (BigInteger.ZERO.equals(v)) {
            if (BigInteger.ZERO.equals(u)) {
                return this.twice(); // this == b, so double
            }

            infinity = true; // this = -b, so infinity
            return R;
        }

        BigInteger THREE = new BigInteger("3");
        BigInteger x1 = this.x;
        BigInteger y1 = this.y;
        BigInteger x2 = b.x;
        BigInteger y2 = b.y;

        BigInteger v2 = v.pow(2);
        BigInteger v3 = v2.multiply(v);
        BigInteger x1v2 = x1.multiply(v2);
        BigInteger zu2 = u.pow(2).multiply(this.z);

        // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
        BigInteger x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).
                subtract(v3).multiply(v).mod(this.ec.getP());
        // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
        BigInteger y3 = x1v2.multiply(THREE).multiply(u).
                subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).
                multiply(b.z).add(u.multiply(v3)).mod(this.ec.getP());
        // z3 = v^3 * z1 * z2
        BigInteger z3 = v3.multiply(this.z).multiply(b.z).mod(this.ec.getP());

        return new ECPointArthimetic(this.ec, x3, y3, z3);
    }

    public ECPointArthimetic twice() {
        if (this.isInfinity()) {
            return this;
        }
        ECPointArthimetic R = new ECPointArthimetic(this.ec, zero, zero, null);
        if (this.y.signum() == 0) {
            infinity = true;
            return R;
        }

        BigInteger THREE = new BigInteger("3");
        BigInteger x1 = this.x;
        BigInteger y1 = this.y;

        BigInteger y1z1 = y1.multiply(this.z);
        BigInteger y1sqz1 = y1z1.multiply(y1).mod(this.ec.getP());
        BigInteger a = this.ec.getA();
        // w = 3 * x1^2 + a * z1^2
        BigInteger w = x1.pow(2).multiply(THREE);
        if (!BigInteger.ZERO.equals(a)) {
            w = w.add(this.z.pow(2).multiply(a));
        }
        w = w.mod(this.ec.getP());
        // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
        BigInteger x3 = w.pow(2).subtract(x1.shiftLeft(3).multiply(y1sqz1)).
                shiftLeft(1).multiply(y1z1).mod(this.ec.getP());
        // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
        BigInteger y3 = (w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1))).
                shiftLeft(2).multiply(y1sqz1).subtract(w.pow(2).multiply(w)).mod(this.ec.getP());
        // z3 = 8 * (y1 * z1)^3
        BigInteger z3 = y1z1.pow(2).multiply(y1z1).shiftLeft(3).mod(this.ec.getP());

        return new ECPointArthimetic(this.ec, x3, y3, z3);
    }

    public ECPointArthimetic multiply(BigInteger k) {
        if (this.isInfinity()) {
            return this;
        }
        ECPointArthimetic R = new ECPointArthimetic(this.ec, zero, zero, null);
        if (k.signum() == 0) {
            infinity = true;
            return R;
        }

        BigInteger e = k;
        BigInteger h = e.multiply(new BigInteger("3"));

        ECPointArthimetic neg = this.negate();
        R = this;

        int i;
        for (i = h.bitLength() - 2; i > 0; --i) {
            R = R.twice();
            boolean hBit = h.testBit(i);
            boolean eBit = e.testBit(i);

            if (hBit != eBit) {
                R = R.add(hBit ? this : neg);
            }
        }

        return R;
    }

    public ECPointArthimetic implShamirsTrick( BigInteger k,
    ECPointArthimetic Q, BigInteger l){
        int m = Math.max(k.bitLength(), l.bitLength());
        ECPointArthimetic Z = this.add(Q);
        ECPointArthimetic R  = new ECPointArthimetic(ec,zero,zero,null);

        for (int i = m - 1; i >= 0; --i){
            R = R.twice();

            if (k.testBit(i)){
                if (l.testBit(i)){
                    R = R.add(Z);
                }else{
                    R = R.add(this);
                }
            }else{
                if (l.testBit(i)){
                    R = R.add(Q);
                }
            }
        }
        return R;
    }
}

这是我使用的曲线:

package NISTCurves;
import ecc.*;
import java.math.BigInteger;

public class P192 implements ECDomainParameters {

    String p192X = "188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012";
    String p192Y = "07192b95ffc8da78631011ed6b24cdd573f977a11e794811";
    String p192B = "64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1";
    String p192P = "6277101735386680763835789423207666416083908700390324961279";
    String p192Order = "6277101735386680763835789423176059013767194773182842284081";
    String p192A = "-3";
    BigInteger p = new BigInteger(p192P, 16);
    EllipticCurve ec =
        new EllipticCurve(p,
        new BigInteger(p192A).mod(p),
        new BigInteger(p192B, 16));
    ECPointArthimetic G = new ECPointArthimetic(ec, new BigInteger(p192X,16), 
               new BigInteger(p192Y,16),null);
    BigInteger order = new BigInteger(p192Order, 16);

    @Override
    public BigInteger getP() {
        return p;
    }

    @Override
    public EllipticCurve getECCurve() {
        return ec;
    }

    @Override
    public BigInteger getOrder() {
        return order;
    }

    @Override
    public ECPointArthimetic getGenerator() {
        return G;
    }
}

椭圆曲线域参数的规范

package NISTCurves;
import ecc.ECPointArthimetic;
import ecc.EllipticCurve;
import java.math.BigInteger;

public interface ECDomainParameters {
    public BigInteger getP();
    public ECPointArthimetic getGenerator();  
    public EllipticCurve getECCurve();
    public BigInteger getOrder();
} 

椭圆曲线数字签名算法实现就在这里。 这段代码中有 main 函数,所以用它来测试异常。

package ecc;
import NISTCurves.ECDomainParameters;
import NISTCurves.P192;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 *
 * @author Gere
 */
public class ECDSA {

    private BigInteger r, s;
    ECDomainParameters param;
    private PrivateKey prvKey;
    private PublicKey pubKey;
    BigInteger zero = BigInteger.ZERO;
    private BigInteger one = BigInteger.ONE;
    private MessageDigest sha;

    public ECDSA() {
        try {
            sha = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
    }

    public void initSign(PrivateKey prvKey) {
        this.prvKey = prvKey;
        param = prvKey.getParam();
    }

    public void initVerify(PublicKey pubKey) {
        this.pubKey = pubKey;
        param = pubKey.getParam();
    }

    public void update(byte[] byteMsg) {
        sha.update(byteMsg);
    }

    public byte[] sign() throws FileNotFoundException, IOException {

        BigInteger c = new BigInteger(
                                   param.getP().bitLength() + 64,  Rand.sr);
        BigInteger k = c.mod(param.getOrder().subtract(one)).add(one);
        while (!(k.gcd(param.getOrder()).compareTo(one) == 0)) {
            c = new BigInteger(param.getP().bitLength() + 64, Rand.sr);
            k = c.mod(param.getOrder().subtract(one)).add(one);
        }
        BigInteger kinv = k.modInverse(param.getOrder());
        ECPointArthimetic p = param.getGenerator().multiply(k);
        if (p.getX().equals(zero)) {
            return sign();
        }
        BigInteger hash = new BigInteger(sha.digest());
        BigInteger r = p.getX().mod(param.getOrder());

        BigInteger s = (kinv.multiply((hash.add((prvKey.getPrivateKey()
                                  .multiply(r)))))).mod(param.getOrder());
        if (s.compareTo(zero) == 0) {
            return sign();
        }

        System.out.println("r at sign: " + r);
        System.out.println("s at sign: " + s);

        byte[] rArr = toUnsignedByteArray(r);
        byte[] sArr = toUnsignedByteArray(s);
        int nLength = (param.getOrder().bitLength() + 7) / 8;
        byte[] res = new byte[2 * nLength];
        System.arraycopy(rArr, 0, res, nLength - rArr.length, rArr.length);

        System.arraycopy(sArr, 0, res, 2 * nLength - sArr.length,
                      sArr.length);
        return res;
    }

    public boolean verify(byte[] res) {

        int nLength = (param.getOrder().bitLength() + 7) / 8;

        byte[] rArr = new byte[nLength];
        System.arraycopy(res, 0, rArr, 0, nLength);
        r = new BigInteger(rArr);

        byte[] sArr = new byte[nLength];
        System.arraycopy(res, nLength, sArr, 0, nLength);
        s = new BigInteger(sArr);
        System.out.println("r at verify: " + r);
        System.out.println("s at verify: " + s);
        BigInteger w, u1, u2, v;
        // r in the range [1,n-1]
        if (r.compareTo(one) < 0 || r.compareTo(param.getOrder()) >= 0) {
            return false;
        }

        // s in the range [1,n-1]
        if (s.compareTo(one) < 0 || s.compareTo(param.getOrder()) >= 0) {
            return false;
        }
        w = s.modInverse(param.getOrder());

        BigInteger hash = new BigInteger(sha.digest());
        u1 = hash.multiply(w);
        u2 = r.multiply(w);

        ECPointArthimetic G = param.getGenerator();
        ECPointArthimetic Q = pubKey.getPublicKey();

        // u1G + u2Q

        ECPointArthimetic temp = G.implShamirsTrick(u1, Q, u2);
        v = temp.getX();
        v = v.mod(param.getOrder());

        return v.equals(r);
    }

    byte[] toUnsignedByteArray(BigInteger bi) {
        byte[] ba = bi.toByteArray();
        if (ba[0] != 0) {
            return ba;
        } else {
            byte[] ba2 = new byte[ba.length - 1];
            System.arraycopy(ba, 1, ba2, 0, ba.length - 1);
            return ba2;
        }
    }

    public static void main(String[] args) {
        byte[] msg = "Hello".getBytes();
        byte[] sig = null;
        ECDomainParameters param = new P192();        
        PrivateKey prvObj = new PrivateKey(param);
        PublicKey pubObj = new PublicKey(prvObj);
        ECDSA ecdsa = new ECDSA();
        ecdsa.initSign(prvObj);
        ecdsa.update(msg);
        try {
            sig = ecdsa.sign();
        } catch (FileNotFoundException ex) {
            System.out.println(ex.getMessage());

        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
        ecdsa.initVerify(pubObj);
        ecdsa.update(msg);
        if (ecdsa.verify(sig)) {
            System.out.println("valid");
        } else {
            System.out.println("invalid");
        }
    }
}

这里是PrivateKey类

package ecc;
import NISTCurves.ECDomainParameters;
import java.math.BigInteger;
import java.security.SecureRandom;

/**
 *
 * @author Gere
 */
public class PrivateKey {

    private BigInteger d;
    private ECDomainParameters param;
    private BigInteger one = BigInteger.ONE;
    private BigInteger zero;
    private PublicKey pubKey;

    public PrivateKey(ECDomainParameters param) {
        this.param = param;
        BigInteger c = new BigInteger(param.getOrder().bitLength() + 64,
                new SecureRandom());
        BigInteger n1 = param.getOrder().subtract(one);
        d = c.mod(n1).add(one);
        pubKey = new PublicKey(this);
    }

    public BigInteger getPrivateKey() {
        return d;
    }

    public ECDomainParameters getParam() {
        return param;
    }
}

公钥类

package ecc;
import NISTCurves.ECDomainParameters;

/**
 *
 * @author Gere
 */
public class PublicKey {
    private ECDomainParameters param;
    private ECPointArthimetic Q;

    public PublicKey(PrivateKey privObj) {
        param = privObj.getParam();
        Q  = param.getGenerator().multiply(privObj.getPrivateKey());
    }

    public ECDomainParameters getParam() {
        return param;
    }

    public ECPointArthimetic getPublicKey() {
        return Q;
    }
}

椭圆曲线

package ecc;
import java.math.BigInteger;

/**
 *
 * @author Gere
 */
public class EllipticCurve {

    private BigInteger a;
    private BigInteger b;
    private BigInteger p;

    public EllipticCurve(BigInteger a, BigInteger b, BigInteger p) {
        this.a = a;
        this.b = b;
        this.p = p;
    }

    public BigInteger getA() {
        return a;
    }

    public BigInteger getB() {
        return b;
    }

    public BigInteger getP() {
        return p;
    }       
}

兰德级

package ecc;
import java.security.SecureRandom;

/**
 *
 * @author Gere
 */
public class Rand {
    public static final SecureRandom sr = new SecureRandom();     
}

椭圆曲线接口

package ecc;
import java.math.BigInteger;

public interface ECConstants{
    public static final BigInteger zero = BigInteger.valueOf(0);
    public static final BigInteger one = BigInteger.valueOf(1);
    public static final BigInteger two = BigInteger.valueOf(2);
    public static final BigInteger three = BigInteger.valueOf(3);
    public static final BigInteger four= BigInteger.valueOf(4);
}

最重要的错误出现在 NISTCurves.P192 中:p 和顺序以 10 为基数,而不是以 16 为基数。此外,当您构造 EllipticCurve 对象时,您以错误的顺序提供参数。你的方法需要(a, b, p),但你用它来称呼它(p, a, b)(所以我的猜测是p不是素数是正确的)。

另一个问题是你的验证方法,当你解开时r and s。由于它们是无符号格式,因此您应该使用new BigInteger(1, rArr)而不是普通的构造函数。

通过这些更改,您的代码对我有用(我可以验证签名 - 我尚未验证实现的正确性)。


(下面是旧答案:)

由于您没有向我们提供与堆栈跟踪匹配的代码,因此这只是一个猜测:

在椭圆曲线加法期间(在素数域上有一条曲线),您应该只调用BigInteger.modInverse()与素数p(素数域的阶数)作为模数。

偶尔失败并出现“BigInteger 不可逆”的最可能方法是:p实际上不是素数。

你从哪里得到p从?尝试插入

if(!ec.getP().isProbablePrime(100)) throw new RuntimeException("P is not a prime");

某处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用此椭圆曲线点乘法计算的点不在曲线上,此类带来算术异常 的相关文章

随机推荐

  • Zend 路线 全部捕获

    请帮忙 我是 Send 新手 想要修改我正在开发的 cms 项目的默认路由 如果控制器不存在 如何在 zend 中创建 捕获所有 路由 我正在尝试创建如下链接 mydomain com slug mydomain com slug1 其中
  • 如何使用 Jackson 序列化基于 java.util.Map 的类

    我有一堂课 看起来像这样 JsonFormat shape JsonFormat Shape OBJECT public class MyMap implements Map
  • 运算符重载 C++:只写版本

    我正在重载数据结构的运算符 因此我有标准函数声明 T operator int i used for regular objects const T operator int i const used for const objects 所
  • 如何禁用 iPhone 上文本输入的拼写检查器

    有时拼写检查器是不必要的 验证码 用户名 电子邮件等 有没有办法在某些文本输入 文本区域禁用它 正如我的好友 Jonathan Stark 所指出的 您应该能够使用自动更正和自动完成等属性来实现您正在寻找的效果
  • 自动对齐双语 Rmarkdown -> LaTeX 文档的文本

    更新 见下文 我正在写一份双语报告 即使用阿拉伯语和英语 使用xelatex引擎 mainfont Arial and lang arYAML 元数据 该文档可以顺利渲染阿拉伯语和英语 经过一段时间后 hustle https stacko
  • Android获取以编程方式创建的视图的宽度

    我以编程方式创建了 TextView 如下所示 TextView mTextView new TextView getApplicationContext final LayoutParams params new TableLayout
  • WPF ListView ScrollBar 可见为 false

    即使需要 是否可以强制水平 或垂直 滚动不显示 问题是我需要根据项目显示不同的颜色 效果很好 但您可以清楚地看到颜色没有到达列表视图的两个边缘 这有点难看 更糟糕的是 我的列表视图中有另一个列表视图 其中包含另一个项目列表 这些项目的背景甚
  • Firefox 中背景图像的过渡?

    我正在尝试为此寻找替代方案 transition background image 1s whatever in firefox因为它只适用于 webkit 浏览器 我已经尝试过不透明度替代方案 但这对我来说不是一个选择 因为我在背景容器上
  • git - 无法拉取或提交

    我在提交和拉取时遇到问题 在提交 IDE 中我看到 warning not all local changes may be shown due to an error unable to read tree 并且只有我的文件提交的一部分在
  • 我可以在我不拥有的类型上使用 DebuggerTypeProxyAttribute 之类的东西吗?

    我有一个IClaimsPrincipal变量 我想看看其中有多少索赔 在监视窗口中导航属性很复杂 因此我想自定义该对象的显示方式 我知道 DebuggerTypeProxy 属性 http msdn microsoft com en us
  • jQuery 美元符号混淆

    我对 jQuery 中的美元符号有点困惑 希望有人能帮助我 我有以下函数声明 function create discussion button click function alert Clicked listitems tr click
  • PHP 的 Curl 无法在 AppEngine 上运行

    在本地 AppEngine 上 curl 请求给出以下结果 这正是我所期望的 url gt https spreadsheets google com feeds spreadsheets private full content type
  • 定时器触发不会触发队列但手动录入会触发-Python

    我有一个队列触发器 当消息手动添加到队列中时 它会启动并按预期运行 但是 当消息通过以下定时器触发函数写入队列时 它无法启动 我可以看到触发器已成功写入消息 init py import datetime import logging im
  • 在 HTTPServlet 请求中编码 UTF-8

    这可能看起来像是一个已经解决的问题 但事实并非如此 因为我已经解决了所有涉及 UTF 8 的问题 但没有一个解决方案对我有帮助 我使用 JSON 简单库向包含 JSON 对象的 java servlet 发送 http 请求 我在Tomca
  • 如何同时针对多种类型专门化方法

    我有这样的代码 template lt class T gt struct Value quite a lot of other functions which I do not want to specialize too void pr
  • LINQ 使用 OR 连接

    我想使用 OR 语句与 LINQ 进行 JOIN 这是我开始的 SQL 查询 SELECT t id FROM Teams t INNER JOIN Games g ON g homeTeamId t id OR g awayTeamId
  • 如何跟踪 WinForms 中任何子控件何时获得或失去焦点?

    我有一个 Windows 窗体自定义控件 其作用类似于面板 因为它可以包含任意数量的子项 子控件的数量和类型是在运行时确定的 因此我需要以通用方式工作 而不知道可能存在或不存在的确切子控件 我想根据面板是否包含焦点来更改面板的背景颜色 因此
  • 在视图导出中获取摘要计数?

    我需要将视图导出到 Excel 我已经在某处找到了一些代码 它在 xpages 中运行得很好 现在用户想要添加总计摘要 我会解释 我有一个包含用户名 项目 ID 和设备 ID 的文档 我需要做的是导出具有特定项目 ID 的所有文档 在导出中
  • 如何在 C# 中更新查询字符串?

    网址中的某处有一个 sortBy 6 如何在单击按钮时将其更新为 sortBy 4 或 sortBy 2 我是否需要编写自定义字符串函数来创建正确的重定向 URL 如果我只需要附加一个查询字符串变量我会这样做 string complete
  • 使用此椭圆曲线点乘法计算的点不在曲线上,此类带来算术异常

    我得到了使用标准投影坐标进行点乘错误的堆栈 我不知道我错过了什么 但相乘的点并不位于曲线上 有时它会输出类似的内容算术异常 整数不可逆 public class ECPointArthimetic EllipticCurve ec priv