1894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanpackage org.bouncycastle.math.ec.custom.sec;
2894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
3894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.math.BigInteger;
4894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
5894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport org.bouncycastle.math.ec.ECFieldElement;
6894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport org.bouncycastle.math.raw.Mod;
7894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport org.bouncycastle.math.raw.Nat256;
8894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport org.bouncycastle.util.Arrays;
9894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
10894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanpublic class SecP256R1FieldElement extends ECFieldElement
11894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman{
12894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final BigInteger Q = SecP256R1Curve.q;
13894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
14894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected int[] x;
15894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
16894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public SecP256R1FieldElement(BigInteger x)
17894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
19894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        {
20894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            throw new IllegalArgumentException("x value invalid for SecP256R1FieldElement");
21894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
22894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
23894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        this.x = SecP256R1Field.fromBigInteger(x);
2419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
2519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
26894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public SecP256R1FieldElement()
27894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
28894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        this.x = Nat256.create();
29894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
30894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
31894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected SecP256R1FieldElement(int[] x)
32894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
33894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        this.x = x;
34894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
35894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
36894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public boolean isZero()
37894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
38894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Nat256.isZero(x);
39894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
40894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
41894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public boolean isOne()
42894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
43894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Nat256.isOne(x);
44894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
45894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
46894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public boolean testBitZero()
47894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
48894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Nat256.getBit(x, 0) == 1;
49894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
50894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
51894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public BigInteger toBigInteger()
52894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
53894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Nat256.toBigInteger(x);
54894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
55894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
56894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public String getFieldName()
57894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
58894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return "SecP256R1Field";
59894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
60894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
61894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public int getFieldSize()
62894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
63894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Q.bitLength();
64894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
65894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
66894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement add(ECFieldElement b)
67894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
68894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
69894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.add(x, ((SecP256R1FieldElement)b).x, z);
70894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return new SecP256R1FieldElement(z);
71894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
72894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
73894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement addOne()
74894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
75894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
76894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.addOne(x, z);
77894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return new SecP256R1FieldElement(z);
78894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
79894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
80894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement subtract(ECFieldElement b)
81894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
82894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
83894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.subtract(x, ((SecP256R1FieldElement)b).x, z);
84894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return new SecP256R1FieldElement(z);
85894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
86894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
87894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement multiply(ECFieldElement b)
88894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
89894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
90894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.multiply(x, ((SecP256R1FieldElement)b).x, z);
91894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return new SecP256R1FieldElement(z);
92894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
93894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
94894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement divide(ECFieldElement b)
95894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
96894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman//        return multiply(b.invert());
97894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
98894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        Mod.invert(SecP256R1Field.P, ((SecP256R1FieldElement)b).x, z);
99894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.multiply(z, x, z);
10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        return new SecP256R1FieldElement(z);
10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    public ECFieldElement negate()
10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    {
105894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
106894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.negate(x, z);
107894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return new SecP256R1FieldElement(z);
108894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
109894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
110894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public ECFieldElement square()
111894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
112894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        int[] z = Nat256.create();
113894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1Field.square(x, z);
11419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        return new SecP256R1FieldElement(z);
11519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
11619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
11719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    public ECFieldElement invert()
11819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    {
11919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//        return new SecP256R1FieldElement(toBigInteger().modInverse(Q));
12019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        int[] z = Nat256.create();
12119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        Mod.invert(SecP256R1Field.P, x, z);
12219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        return new SecP256R1FieldElement(z);
12319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
12419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
12519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    /**
12619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * return a sqrt root - the routine verifies that the calculation returns the right value - if
12719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * none exists it returns null.
12819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     */
12919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    public ECFieldElement sqrt()
13019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    {
13119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94
13219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        int[] x1 = this.x;
13419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if (Nat256.isZero(x1) || Nat256.isOne(x1))
13519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        {
13619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            return this;
13719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        }
13819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        int[] t1 = Nat256.create();
14019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        int[] t2 = Nat256.create();
14119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.square(x1, t1);
14319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t1, x1, t1);
14419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t1, 2, t2);
14619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t2, t1, t2);
14719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t2, 4, t1);
14919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t1, t2, t1);
15019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t1, 8, t2);
15219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t2, t1, t2);
15319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t2, 16, t1);
15519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t1, t2, t1);
15619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t1, 32, t1);
15819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t1, x1, t1);
15919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t1, 96, t1);
16119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.multiply(t1, x1, t1);
16219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.squareN(t1, 94, t1);
16419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        SecP256R1Field.square(t1, t2);
16519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        return Nat256.eq(x1, t2) ? new SecP256R1FieldElement(t1) : null;
16719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
16819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    public boolean equals(Object other)
17019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    {
17119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if (other == this)
17219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        {
17319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            return true;
174894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
175894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
176894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!(other instanceof SecP256R1FieldElement))
177894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        {
178894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return false;
179894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
180894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
181894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        SecP256R1FieldElement o = (SecP256R1FieldElement)other;
182894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Nat256.eq(x, o.x);
183894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
184894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
185894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public int hashCode()
186894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    {
187894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
188894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
189894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman}
190894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman