mirror of https://github.com/hyperledger/besu
add bandersnatch point (#4647)
* add bandersnatch point Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * fix build Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * fix build Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * fix build Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * fix build Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * spotless Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * comment test Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> * Update ethereum/verkletrie/src/main/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/Element.java Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com> Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com>pull/4803/head
parent
9006445147
commit
f9bc1b76e4
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
apply plugin: 'java-library' |
||||||
|
|
||||||
|
jar { |
||||||
|
archiveBaseName = 'besu-verkletrie' |
||||||
|
manifest { |
||||||
|
attributes( |
||||||
|
'Specification-Title': archiveBaseName, |
||||||
|
'Specification-Version': project.version, |
||||||
|
'Implementation-Title': archiveBaseName, |
||||||
|
'Implementation-Version': calculateVersion() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
implementation project(':crypto') |
||||||
|
implementation project(':ethereum:rlp') |
||||||
|
implementation project(':ethereum:trie') |
||||||
|
|
||||||
|
implementation "org.immutables:value-annotations" |
||||||
|
implementation 'com.google.guava:guava' |
||||||
|
implementation 'io.opentelemetry:opentelemetry-api' |
||||||
|
implementation 'org.apache.tuweni:tuweni-bytes' |
||||||
|
implementation 'org.bouncycastle:bcprov-jdk15on' |
||||||
|
implementation 'org.hyperledger.besu:ipa-multipoint' |
||||||
|
|
||||||
|
annotationProcessor "org.immutables:value" |
||||||
|
|
||||||
|
testImplementation project(':services:kvstore') |
||||||
|
testImplementation project(':testutil') |
||||||
|
|
||||||
|
testImplementation 'com.fasterxml.jackson.core:jackson-databind' |
||||||
|
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' |
||||||
|
testImplementation 'junit:junit' |
||||||
|
testImplementation 'org.apache.tuweni:tuweni-units' |
||||||
|
testImplementation 'org.assertj:assertj-core' |
||||||
|
testImplementation 'org.junit.jupiter:junit-jupiter' |
||||||
|
testImplementation 'org.mockito:mockito-core' |
||||||
|
|
||||||
|
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fp.Element; |
||||||
|
|
||||||
|
import java.nio.ByteOrder; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
|
||||||
|
public class Point { |
||||||
|
|
||||||
|
public static final Point EMPTY = new Point(Element.ZERO, Element.ZERO, Element.ZERO); |
||||||
|
public static final Point IDENTITY = new Point(Element.ZERO, Element.ONE, Element.ONE); |
||||||
|
public final Element x; |
||||||
|
public final Element y; |
||||||
|
public final Element z; |
||||||
|
|
||||||
|
public Point(final Element x, final Element y, final Element z) { |
||||||
|
this.x = x; |
||||||
|
this.y = y; |
||||||
|
this.z = z; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "Point{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 mapToBaseFieldBytes() { |
||||||
|
Element res = x.divide(y); |
||||||
|
return res.getBytes(ByteOrder.LITTLE_ENDIAN); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 bytes() { |
||||||
|
PointAffine affineRepresentation = PointAffine.fromProj(this); |
||||||
|
Element x = affineRepresentation.x; |
||||||
|
if (!affineRepresentation.y.lexicographicallyLargest()) { |
||||||
|
x = x.neg(); |
||||||
|
} |
||||||
|
return x.getBytes(ByteOrder.BIG_ENDIAN); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fp.Element; |
||||||
|
|
||||||
|
public class PointAffine { |
||||||
|
|
||||||
|
final Element x; |
||||||
|
final Element y; |
||||||
|
|
||||||
|
public PointAffine(final Element x, final Element y) { |
||||||
|
this.x = x; |
||||||
|
this.y = y; |
||||||
|
} |
||||||
|
|
||||||
|
public static PointAffine fromProj(final Point point) { |
||||||
|
return new PointAffine(point.x.divide(point.z), point.y.divide(point.z)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,526 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fp; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.nio.ByteOrder; |
||||||
|
import java.util.Objects; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.apache.tuweni.bytes.MutableBytes32; |
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
|
||||||
|
public class Element { |
||||||
|
public static final Element ZERO = new Element(UInt256.ZERO); |
||||||
|
public static final Element ONE; |
||||||
|
static final Element Q_MODULUS; |
||||||
|
private static final Element R_SQUARE; |
||||||
|
|
||||||
|
static { |
||||||
|
{ |
||||||
|
// z0, z1, z2 and z3 represent the 4 limbs of element
|
||||||
|
// `0` in Montgomery form.
|
||||||
|
UInt256 z0 = UInt256.valueOf(8589934590L); |
||||||
|
UInt256 z1 = UInt256.valueOf(6378425256633387010L).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("11064306276430008309", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(1739710354780652911L).shiftLeft(192); |
||||||
|
ONE = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
{ |
||||||
|
UInt256 z0 = UInt256.valueOf(new BigInteger("18446744069414584321", 10)); |
||||||
|
UInt256 z1 = UInt256.valueOf(new BigInteger("6034159408538082302", 10)).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("3691218898639771653", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(new BigInteger("8353516859464449352", 10)).shiftLeft(192); |
||||||
|
Q_MODULUS = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
{ |
||||||
|
UInt256 z0 = UInt256.valueOf(new BigInteger("14526898881837571181", 10)); |
||||||
|
UInt256 z1 = UInt256.valueOf(new BigInteger("3129137299524312099", 10)).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("419701826671360399", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(new BigInteger("524908885293268753", 10)).shiftLeft(192); |
||||||
|
R_SQUARE = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Element random() { |
||||||
|
UInt256 value = UInt256.fromBytes(Bytes32.random()); |
||||||
|
UInt256 divisor = UInt256.fromBytes(Bytes32.rightPad(Q_MODULUS.value.slice(8))); |
||||||
|
value = value.mod(divisor); |
||||||
|
|
||||||
|
if (value.greaterThan(Q_MODULUS.value)) { |
||||||
|
value = value.subtract(Q_MODULUS.value); |
||||||
|
} |
||||||
|
return new Element(value); |
||||||
|
} |
||||||
|
|
||||||
|
final UInt256 value; |
||||||
|
|
||||||
|
public Element(final UInt256 value) { |
||||||
|
this.value = value; |
||||||
|
} |
||||||
|
|
||||||
|
public static Element fromBytes(final Bytes data, final ByteOrder byteOrder) { |
||||||
|
return new Element( |
||||||
|
UInt256.fromBytes(byteOrder == ByteOrder.BIG_ENDIAN ? data : data.reverse())); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean biggerModulus() { |
||||||
|
return value.greaterOrEqualThan(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
public Element inverse() { |
||||||
|
if (isZero()) { |
||||||
|
return new Element(UInt256.ZERO); |
||||||
|
} |
||||||
|
UInt256 u = Q_MODULUS.value; |
||||||
|
UInt256 s = R_SQUARE.value; |
||||||
|
UInt256 v = value; |
||||||
|
UInt256 r = UInt256.ZERO; |
||||||
|
while (true) { |
||||||
|
while ((v.getLong(24) & 1L) == 0) { |
||||||
|
v = v.shiftRight(1); |
||||||
|
if ((s.getLong(24) & 1L) == 1) { |
||||||
|
s = s.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
s = s.shiftRight(1); |
||||||
|
} |
||||||
|
while ((u.getLong(24) & 1L) == 0) { |
||||||
|
u = u.shiftRight(1); |
||||||
|
if ((r.getLong(24) & 1L) == 1) { |
||||||
|
r = r.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
r = r.shiftRight(1); |
||||||
|
} |
||||||
|
boolean bigger = v.greaterOrEqualThan(u); |
||||||
|
if (bigger) { |
||||||
|
v = v.subtract(u); |
||||||
|
UInt256 oldS = s; |
||||||
|
s = s.subtract(r); |
||||||
|
if (s.greaterThan(oldS)) { |
||||||
|
s = s.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
u = u.subtract(v); |
||||||
|
UInt256 oldR = r; |
||||||
|
r = r.subtract(s); |
||||||
|
if (r.greaterThan(oldR)) { |
||||||
|
r = r.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
} |
||||||
|
if (u.getLong(24) == 1L && u.shiftRight(8).equals(UInt256.ZERO)) { |
||||||
|
return new Element(r); |
||||||
|
} |
||||||
|
if (v.getLong(24) == 1L && v.shiftRight(8).equals(UInt256.ZERO)) { |
||||||
|
return new Element(s); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Element neg() { |
||||||
|
if (isZero()) { |
||||||
|
return this; |
||||||
|
} |
||||||
|
return new Element(Q_MODULUS.value.subtract(this.value)); |
||||||
|
} |
||||||
|
|
||||||
|
public byte[] limb(final int i) { |
||||||
|
return value.slice(32 - (i + 1) * 8, 8).toArrayUnsafe(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isZero() { |
||||||
|
return value.isZero(); |
||||||
|
} |
||||||
|
|
||||||
|
public Element divide(final Element b) { |
||||||
|
Element bInv = b.inverse(); |
||||||
|
return this.multiply(bInv); |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd0(final UInt256 a, final UInt256 b, final UInt256 c) { |
||||||
|
UInt256 product = a.multiply(b).add(c); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd1(final UInt256 a, final UInt256 b, final UInt256 c) { |
||||||
|
UInt256 product = a.multiply(b).add(c); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd2(final UInt256 a, final UInt256 b, final UInt256 c, final UInt256 d) { |
||||||
|
UInt256 product = a.multiply(b).add(c).add(d); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd3( |
||||||
|
final UInt256 a, final UInt256 b, final UInt256 c, final UInt256 d, final UInt256 e) { |
||||||
|
UInt256 product = a.multiply(b); |
||||||
|
product = product.add(c).add(d); |
||||||
|
product = product.add(e.shiftLeft(64)); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 limb(final UInt256 value, final int index) { |
||||||
|
return UInt256.fromBytes(Bytes32.leftPad(value.slice(32 - (index + 1) * 8, 8))); |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 setLimb(final UInt256 value, final UInt256 limb, final int index) { |
||||||
|
MutableBytes32 mutable = value.toBytes().mutableCopy(); |
||||||
|
mutable.set(32 - (index + 1) * 8, limb.slice(24, 8)); |
||||||
|
return UInt256.fromBytes(mutable); |
||||||
|
} |
||||||
|
|
||||||
|
public Element multiply(final Element y) { |
||||||
|
|
||||||
|
UInt256 t = UInt256.ZERO; |
||||||
|
UInt256 c; |
||||||
|
|
||||||
|
// round 0
|
||||||
|
{ |
||||||
|
// v := x[0]
|
||||||
|
UInt256 v = limb(this.value, 0); |
||||||
|
// c[1], c[0] = bits.Mul64(v, y[0])
|
||||||
|
UInt256 tempC = v.multiply(limb(y.value, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// m := c[0] * 18446744069414584319
|
||||||
|
UInt256 constant = UInt256.valueOf(new BigInteger("18446744069414584319", 10)); |
||||||
|
UInt256 c0 = limb(c, 0); |
||||||
|
UInt256 m = limb(constant.multiply(c0), 0); |
||||||
|
|
||||||
|
// c[2] = madd0(m, 18446744069414584321, c[0])
|
||||||
|
UInt256 c2 = |
||||||
|
madd0(m, UInt256.valueOf(new BigInteger("18446744069414584321", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd1(v, y[1], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 1), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("6034159408538082302", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd1(v, y[2], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 2), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("3691218898639771653", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd1(v, y[3], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 3), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("8353516859464449352", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 1
|
||||||
|
{ |
||||||
|
UInt256 v = limb(this.value, 1); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 18446744069414584319
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb( |
||||||
|
UInt256.valueOf(new BigInteger("18446744069414584319", 10)).multiply(limb(c, 0)), |
||||||
|
0), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 18446744069414584321, c[0])
|
||||||
|
UInt256 c2 = |
||||||
|
madd0(m, UInt256.valueOf(new BigInteger("18446744069414584321", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("6034159408538082302", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("3691218898639771653", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
|
||||||
|
// t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("8353516859464449352", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 2
|
||||||
|
{ |
||||||
|
// v := x[2]
|
||||||
|
UInt256 v = limb(this.value, 2); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 18446744069414584319
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb(c, 0).multiply(UInt256.valueOf(new BigInteger("18446744069414584319", 10))), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 18446744069414584321, c[0])
|
||||||
|
UInt256 c2 = |
||||||
|
madd0(m, UInt256.valueOf(new BigInteger("18446744069414584321", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("6034159408538082302", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("3691218898639771653", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("8353516859464449352", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 3
|
||||||
|
{ |
||||||
|
// v := x[3]
|
||||||
|
UInt256 v = limb(this.value, 3); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 18446744069414584319
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb(c, 0).multiply(UInt256.valueOf(new BigInteger("18446744069414584319", 10))), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 18446744069414584321, c[0])
|
||||||
|
UInt256 c2 = |
||||||
|
madd0(m, UInt256.valueOf(new BigInteger("18446744069414584321", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], z[0] = madd2(m, 6034159408538082302, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("6034159408538082302", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], z[1] = madd2(m, 3691218898639771653, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("3691218898639771653", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// z[3], z[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("8353516859464449352", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
|
||||||
|
if (t.greaterThan(Q_MODULUS.value)) { |
||||||
|
t = t.subtract(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
return new Element(t); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean lexicographicallyLargest() { |
||||||
|
return value.greaterThan((Q_MODULUS.value.subtract(1)).divide(2)); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getValue(final ByteOrder byteOrder) { |
||||||
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
||||||
|
return this.value; |
||||||
|
} else { |
||||||
|
return (Bytes32) this.value.reverse(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getBytes(final ByteOrder byteOrder) { |
||||||
|
Element toRegular = fromMontgomery(); |
||||||
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
||||||
|
return toRegular.value; |
||||||
|
} else { |
||||||
|
return (Bytes32) toRegular.value.reverse(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(final Object o) { |
||||||
|
if (this == o) return true; |
||||||
|
if (o == null || getClass() != o.getClass()) return false; |
||||||
|
Element element = (Element) o; |
||||||
|
return Objects.equals(value, element.value); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
return Objects.hash(value); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "Element{" + "value=" + value + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 add(final UInt256 z) { |
||||||
|
UInt256 mutableZ = z; |
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
// m := z[0] * 18446744069414584319
|
||||||
|
UInt256 z0 = limb(mutableZ, 0); |
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
UInt256.valueOf(new BigInteger("18446744069414584319", 10)).multiply(z0), |
||||||
|
0); |
||||||
|
// C := madd0(m, 18446744069414584321, z[0])
|
||||||
|
UInt256 tempC = madd0(m, limb(Q_MODULUS.value, 0), limb(mutableZ, 0)); |
||||||
|
UInt256 c = setLimb(UInt256.ZERO, limb(tempC, 1), 0); |
||||||
|
// C, z[0] = madd2(m, 6034159408538082302, z[1], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 1), limb(mutableZ, 1), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 0); |
||||||
|
// C, z[1] = madd2(m, 3691218898639771653, z[2], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 2), limb(mutableZ, 2), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 1); |
||||||
|
// C, z[2] = madd2(m, 8353516859464449352, z[3], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 3), limb(mutableZ, 3), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 2); |
||||||
|
// z[3] = C
|
||||||
|
mutableZ = setLimb(mutableZ, limb(c, 0), 3); |
||||||
|
return mutableZ; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* fromMontgomery converts the element from Montgomery to regular representation sets and returns |
||||||
|
* z = z * 1 |
||||||
|
* |
||||||
|
* @return z * 1 |
||||||
|
*/ |
||||||
|
public Element fromMontgomery() { |
||||||
|
UInt256 calc = add(this.value); |
||||||
|
calc = add(calc); |
||||||
|
calc = add(calc); |
||||||
|
calc = add(calc); |
||||||
|
|
||||||
|
if (calc.greaterThan(Q_MODULUS.value)) { |
||||||
|
return new Element(calc.subtract(Q_MODULUS.value)); |
||||||
|
} |
||||||
|
return new Element(calc); |
||||||
|
} |
||||||
|
|
||||||
|
public Element toMontgomery() { |
||||||
|
return multiply(Element.R_SQUARE); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,508 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fr; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.nio.ByteOrder; |
||||||
|
import java.util.Objects; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.apache.tuweni.bytes.MutableBytes32; |
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
|
||||||
|
public class Element { |
||||||
|
public static final Element ZERO = new Element(UInt256.ZERO); |
||||||
|
public static final Element ONE; |
||||||
|
static final Element Q_MODULUS; |
||||||
|
private static final Element R_SQUARE; |
||||||
|
|
||||||
|
static { |
||||||
|
{ |
||||||
|
UInt256 z0 = UInt256.valueOf(new BigInteger("6347764673676886264", 10)); |
||||||
|
UInt256 z1 = UInt256.valueOf(new BigInteger("253265890806062196", 10)).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("11064306276430008312", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(new BigInteger("1739710354780652911", 10)).shiftLeft(192); |
||||||
|
ONE = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
{ |
||||||
|
UInt256 z0 = UInt256.valueOf(new BigInteger("8429901452645165025", 10)); |
||||||
|
UInt256 z1 = UInt256.valueOf(new BigInteger("18415085837358793841", 10)).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("922804724659942912", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(new BigInteger("2088379214866112338", 10)).shiftLeft(192); |
||||||
|
Q_MODULUS = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
{ |
||||||
|
UInt256 z0 = UInt256.valueOf(new BigInteger("15831548891076708299", 10)); |
||||||
|
UInt256 z1 = UInt256.valueOf(new BigInteger("4682191799977818424", 10)).shiftLeft(64); |
||||||
|
UInt256 z2 = UInt256.valueOf(new BigInteger("12294384630081346794", 10)).shiftLeft(128); |
||||||
|
UInt256 z3 = UInt256.valueOf(new BigInteger("785759240370973821", 10)).shiftLeft(192); |
||||||
|
R_SQUARE = new Element(z0.add(z1).add(z2).add(z3)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Element random() { |
||||||
|
UInt256 value = UInt256.fromBytes(Bytes32.random()); |
||||||
|
UInt256 divisor = UInt256.fromBytes(Bytes32.rightPad(Q_MODULUS.value.slice(8))); |
||||||
|
value = value.mod(divisor); |
||||||
|
|
||||||
|
if (value.greaterThan(Q_MODULUS.value)) { |
||||||
|
value = value.subtract(Q_MODULUS.value); |
||||||
|
} |
||||||
|
return new Element(value); |
||||||
|
} |
||||||
|
|
||||||
|
final UInt256 value; |
||||||
|
|
||||||
|
public Element(final UInt256 value) { |
||||||
|
this.value = value; |
||||||
|
} |
||||||
|
|
||||||
|
public static Element fromBytes(final Bytes data, final ByteOrder byteOrder) { |
||||||
|
return new Element( |
||||||
|
UInt256.fromBytes(byteOrder == ByteOrder.BIG_ENDIAN ? data : data.reverse())); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean biggerModulus() { |
||||||
|
return value.greaterOrEqualThan(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
public Element inverse() { |
||||||
|
if (isZero()) { |
||||||
|
return new Element(UInt256.ZERO); |
||||||
|
} |
||||||
|
UInt256 u = Q_MODULUS.value; |
||||||
|
UInt256 s = R_SQUARE.value; |
||||||
|
UInt256 v = value; |
||||||
|
UInt256 r = UInt256.ZERO; |
||||||
|
while (true) { |
||||||
|
while ((v.getLong(24) & 1L) == 0) { |
||||||
|
v = v.shiftRight(1); |
||||||
|
if ((s.getLong(24) & 1L) == 1) { |
||||||
|
s = s.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
s = s.shiftRight(1); |
||||||
|
} |
||||||
|
while ((u.getLong(24) & 1L) == 0) { |
||||||
|
u = u.shiftRight(1); |
||||||
|
if ((r.getLong(24) & 1L) == 1) { |
||||||
|
r = r.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
r = r.shiftRight(1); |
||||||
|
} |
||||||
|
boolean bigger = v.greaterOrEqualThan(u); |
||||||
|
if (bigger) { |
||||||
|
v = v.subtract(u); |
||||||
|
UInt256 oldS = s; |
||||||
|
s = s.subtract(r); |
||||||
|
if (s.greaterThan(oldS)) { |
||||||
|
s = s.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
u = u.subtract(v); |
||||||
|
UInt256 oldR = r; |
||||||
|
r = r.subtract(s); |
||||||
|
if (r.greaterThan(oldR)) { |
||||||
|
r = r.add(Q_MODULUS.value); |
||||||
|
} |
||||||
|
} |
||||||
|
if (u.getLong(24) == 1L && u.shiftRight(8).equals(UInt256.ZERO)) { |
||||||
|
return new Element(r); |
||||||
|
} |
||||||
|
if (v.getLong(24) == 1L && v.shiftRight(8).equals(UInt256.ZERO)) { |
||||||
|
return new Element(s); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Element neg() { |
||||||
|
if (isZero()) { |
||||||
|
return this; |
||||||
|
} |
||||||
|
return new Element(Q_MODULUS.value.subtract(this.value)); |
||||||
|
} |
||||||
|
|
||||||
|
public byte[] limb(final int i) { |
||||||
|
return value.slice(32 - (i + 1) * 8, 8).toArrayUnsafe(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isZero() { |
||||||
|
return value.isZero(); |
||||||
|
} |
||||||
|
|
||||||
|
public Element divide(final Element b) { |
||||||
|
Element bInv = b.inverse(); |
||||||
|
return this.multiply(bInv); |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd0(final UInt256 a, final UInt256 b, final UInt256 c) { |
||||||
|
UInt256 product = a.multiply(b).add(c); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd1(final UInt256 a, final UInt256 b, final UInt256 c) { |
||||||
|
UInt256 product = a.multiply(b).add(c); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd2(final UInt256 a, final UInt256 b, final UInt256 c, final UInt256 d) { |
||||||
|
UInt256 product = a.multiply(b).add(c).add(d); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 madd3( |
||||||
|
final UInt256 a, final UInt256 b, final UInt256 c, final UInt256 d, final UInt256 e) { |
||||||
|
UInt256 product = a.multiply(b); |
||||||
|
product = product.add(c).add(d); |
||||||
|
product = product.add(e.shiftLeft(64)); |
||||||
|
return product; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 limb(final UInt256 value, final int index) { |
||||||
|
return UInt256.fromBytes(Bytes32.leftPad(value.slice(32 - (index + 1) * 8, 8))); |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 setLimb(final UInt256 value, final UInt256 limb, final int index) { |
||||||
|
MutableBytes32 mutable = value.toBytes().mutableCopy(); |
||||||
|
mutable.set(32 - (index + 1) * 8, limb.slice(24, 8)); |
||||||
|
return UInt256.fromBytes(mutable); |
||||||
|
} |
||||||
|
|
||||||
|
public Element multiply(final Element y) { |
||||||
|
|
||||||
|
UInt256 t = UInt256.ZERO; |
||||||
|
UInt256 c; |
||||||
|
|
||||||
|
// round 0
|
||||||
|
{ |
||||||
|
// v := x[0]
|
||||||
|
UInt256 v = limb(this.value, 0); |
||||||
|
// c[1], c[0] = bits.Mul64(v, y[0])
|
||||||
|
UInt256 tempC = v.multiply(limb(y.value, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// m := c[0] * 17410672245482742751
|
||||||
|
UInt256 constant = UInt256.valueOf(new BigInteger("17410672245482742751", 10)); |
||||||
|
UInt256 c0 = limb(c, 0); |
||||||
|
UInt256 m = limb(constant.multiply(c0), 0); |
||||||
|
|
||||||
|
// c[2] = madd0(m, 8429901452645165025, c[0])
|
||||||
|
UInt256 c2 = madd0(m, UInt256.valueOf(new BigInteger("8429901452645165025", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd1(v, y[1], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 1), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 18415085837358793841, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("18415085837358793841", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd1(v, y[2], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 2), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 922804724659942912, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, UInt256.valueOf(new BigInteger("922804724659942912", 10)), limb(c, 2), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd1(v, y[3], c[1])
|
||||||
|
tempC = madd1(v, limb(y.value, 3), limb(c, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// t[3], t[2] = madd3(m, 2088379214866112338, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("2088379214866112338", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 1
|
||||||
|
{ |
||||||
|
UInt256 v = limb(this.value, 1); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 17410672245482742751
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb( |
||||||
|
UInt256.valueOf(new BigInteger("17410672245482742751", 10)).multiply(limb(c, 0)), |
||||||
|
0), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 8429901452645165025, c[0])
|
||||||
|
UInt256 c2 = madd0(m, UInt256.valueOf(new BigInteger("8429901452645165025", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 18415085837358793841, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("18415085837358793841", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 922804724659942912, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, UInt256.valueOf(new BigInteger("922804724659942912", 10)), limb(c, 2), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
|
||||||
|
// t[3], t[2] = madd3(m, 2088379214866112338, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("2088379214866112338", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 2
|
||||||
|
{ |
||||||
|
// v := x[2]
|
||||||
|
UInt256 v = limb(this.value, 2); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 17410672245482742751
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb(c, 0).multiply(UInt256.valueOf(new BigInteger("17410672245482742751", 10))), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 8429901452645165025, c[0])
|
||||||
|
UInt256 c2 = madd0(m, UInt256.valueOf(new BigInteger("8429901452645165025", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[0] = madd2(m, 18415085837358793841, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("18415085837358793841", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], t[1] = madd2(m, 922804724659942912, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, UInt256.valueOf(new BigInteger("922804724659942912", 10)), limb(c, 2), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// t[3], t[2] = madd3(m, 2088379214866112338, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("2088379214866112338", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
// round 3
|
||||||
|
{ |
||||||
|
// v := x[3]
|
||||||
|
UInt256 v = limb(this.value, 3); |
||||||
|
// c[1], c[0] = madd1(v, y[0], t[0])
|
||||||
|
UInt256 tempC = madd1(v, limb(y.value, 0), limb(t, 0)); |
||||||
|
c = setLimb(UInt256.ZERO, limb(tempC, 0), 0); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
// m := c[0] * 17410672245482742751
|
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
limb(c, 0).multiply(UInt256.valueOf(new BigInteger("17410672245482742751", 10))), |
||||||
|
0); |
||||||
|
// c[2] = madd0(m, 8429901452645165025, c[0])
|
||||||
|
UInt256 c2 = madd0(m, UInt256.valueOf(new BigInteger("8429901452645165025", 10)), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(c2, 1), 2); |
||||||
|
// c[1], c[0] = madd2(v, y[1], c[1], t[1])
|
||||||
|
tempC = madd2(v, limb(y.value, 1), limb(c, 1), limb(t, 1)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], z[0] = madd2(m, 18415085837358793841, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("18415085837358793841", 10)), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 0); |
||||||
|
// c[1], c[0] = madd2(v, y[2], c[1], t[2])
|
||||||
|
tempC = madd2(v, limb(y.value, 2), limb(c, 1), limb(t, 2)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// c[2], z[1] = madd2(m, 922804724659942912, c[2], c[0])
|
||||||
|
tempC = |
||||||
|
madd2( |
||||||
|
m, UInt256.valueOf(new BigInteger("922804724659942912", 10)), limb(c, 2), limb(c, 0)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 2); |
||||||
|
t = setLimb(t, limb(tempC, 0), 1); |
||||||
|
// c[1], c[0] = madd2(v, y[3], c[1], t[3])
|
||||||
|
tempC = madd2(v, limb(y.value, 3), limb(c, 1), limb(t, 3)); |
||||||
|
c = setLimb(c, limb(tempC, 1), 1); |
||||||
|
c = setLimb(c, limb(tempC, 0), 0); |
||||||
|
// z[3], z[2] = madd3(m, 2088379214866112338, c[0], c[2], c[1])
|
||||||
|
tempC = |
||||||
|
madd3( |
||||||
|
m, |
||||||
|
UInt256.valueOf(new BigInteger("2088379214866112338", 10)), |
||||||
|
limb(c, 0), |
||||||
|
limb(c, 2), |
||||||
|
limb(c, 1)); |
||||||
|
t = setLimb(t, limb(tempC, 1), 3); |
||||||
|
t = setLimb(t, limb(tempC, 0), 2); |
||||||
|
} |
||||||
|
|
||||||
|
if (t.greaterThan(Q_MODULUS.value)) { |
||||||
|
t = t.subtract(Q_MODULUS.value); |
||||||
|
} |
||||||
|
|
||||||
|
return new Element(t); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean lexicographicallyLargest() { |
||||||
|
return value.greaterThan((Q_MODULUS.value.subtract(1)).divide(2)); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getValue(final ByteOrder byteOrder) { |
||||||
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
||||||
|
return this.value; |
||||||
|
} else { |
||||||
|
return (Bytes32) this.value.reverse(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getBytes(final ByteOrder byteOrder) { |
||||||
|
Element toRegular = fromMontgomery(); |
||||||
|
if (byteOrder == ByteOrder.BIG_ENDIAN) { |
||||||
|
return toRegular.value; |
||||||
|
} else { |
||||||
|
return (Bytes32) toRegular.value.reverse(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(final Object o) { |
||||||
|
if (this == o) return true; |
||||||
|
if (o == null || getClass() != o.getClass()) return false; |
||||||
|
Element element = (Element) o; |
||||||
|
return Objects.equals(value, element.value); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
return Objects.hash(value); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "Element{" + "value=" + value + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
private UInt256 add(final UInt256 z) { |
||||||
|
UInt256 mutableZ = z; |
||||||
|
// m = z[0]n'[0] mod W
|
||||||
|
// m := z[0] * 17410672245482742751
|
||||||
|
UInt256 z0 = limb(mutableZ, 0); |
||||||
|
UInt256 m = |
||||||
|
setLimb( |
||||||
|
UInt256.ZERO, |
||||||
|
UInt256.valueOf(new BigInteger("17410672245482742751", 10)).multiply(z0), |
||||||
|
0); |
||||||
|
// C := madd0(m, 8429901452645165025, z[0])
|
||||||
|
UInt256 tempC = madd0(m, limb(Q_MODULUS.value, 0), limb(mutableZ, 0)); |
||||||
|
UInt256 c = setLimb(UInt256.ZERO, limb(tempC, 1), 0); |
||||||
|
// C, z[0] = madd2(m, 18415085837358793841, z[1], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 1), limb(mutableZ, 1), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 0); |
||||||
|
// C, z[1] = madd2(m, 922804724659942912, z[2], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 2), limb(mutableZ, 2), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 1); |
||||||
|
// C, z[2] = madd2(m, 2088379214866112338, z[3], C)
|
||||||
|
tempC = madd2(m, limb(Q_MODULUS.value, 3), limb(mutableZ, 3), c); |
||||||
|
c = setLimb(c, limb(tempC, 1), 0); |
||||||
|
mutableZ = setLimb(mutableZ, limb(tempC, 0), 2); |
||||||
|
// z[3] = C
|
||||||
|
mutableZ = setLimb(mutableZ, limb(c, 0), 3); |
||||||
|
return mutableZ; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* fromMontgomery converts the element from Montgomery to regular representation sets and returns |
||||||
|
* z = z * 1 |
||||||
|
* |
||||||
|
* @return z * 1 |
||||||
|
*/ |
||||||
|
public Element fromMontgomery() { |
||||||
|
UInt256 calc = add(this.value); |
||||||
|
calc = add(calc); |
||||||
|
calc = add(calc); |
||||||
|
calc = add(calc); |
||||||
|
|
||||||
|
if (calc.greaterThan(Q_MODULUS.value)) { |
||||||
|
return new Element(calc.subtract(Q_MODULUS.value)); |
||||||
|
} |
||||||
|
return new Element(calc); |
||||||
|
} |
||||||
|
|
||||||
|
public Element toMontgomery() { |
||||||
|
return multiply(R_SQUARE); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,220 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fp; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class ElementTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testIsZero() { |
||||||
|
assertThat(Element.ZERO.isZero()).isTrue(); |
||||||
|
assertThat(Element.ONE.isZero()).isFalse(); |
||||||
|
assertThat(new Element(UInt256.valueOf(42L)).isZero()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverseZero() { |
||||||
|
Element elt = Element.ZERO; |
||||||
|
assertThat(elt.inverse()).isEqualTo(elt); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverse42() { |
||||||
|
assertThat(new Element(UInt256.valueOf(42L)).inverse()) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"3fa8731a5789261bc0c32da675b6100c6bd8289edea72861d409c282e75503ba"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverseOverQ() { |
||||||
|
assertThat(new Element(Element.Q_MODULUS.value.add(1)).inverse()) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0748d9d99f59ff1105d314967254398f2b6cedcb87925c23c999e990f3f29c6d"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testRandom() { |
||||||
|
assertThat(Element.random().value.lessOrEqualThan(Element.Q_MODULUS.value)).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDivide() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d433339d80809a1d80253bda402fffe5bfcfffffffefffffff3")); |
||||||
|
Element y = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d753339d80809a1d7d553bda402fffe5c1cfffffffeffffffe9")); |
||||||
|
assertThat(x.divide(y)) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"42291ebda05409e31e85f7061384f4066381dbac31023c5f2609827a639d6ddc"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testMultiply() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d433339d80809a1d80253bda402fffe5bfcfffffffefffffff3")); |
||||||
|
Element y = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d753339d80809a1d7d553bda402fffe5c1cfffffffeffffffe9")); |
||||||
|
assertThat(x.multiply(y)) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"addbab1d634d4bbc1c11001562f72e2a24caa1b482c2f2038b3a8d46bf1416f"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNeg() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"05f98ae63ff2eb86b466cc60a939dd4adaeed3599e3ad7a34694ff6dbf518a76")); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"6df41c6ce9aa91c17ed30ba76067faba78ced0a961c3845bb96b009140ae758b")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegOverQ() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegZero() { |
||||||
|
Element x = Element.ZERO; |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value).isEqualTo(Element.ZERO.value); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegOne() { |
||||||
|
Element x = new Element(UInt256.ONE); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testFromMont() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.fromMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"1bbe869330009d577204078a4f77266aab6fca8f09dc705f13f75b69fe75c040")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testToMont() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.toMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0x1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testToMont2() { |
||||||
|
Element before = |
||||||
|
new Element( |
||||||
|
UInt256.valueOf(new BigInteger("999881962499998002", 10)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(64)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("1", 10)).shiftLeft(128)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(192))); |
||||||
|
Element expected = |
||||||
|
new Element( |
||||||
|
UInt256.valueOf(new BigInteger("479530773443910689", 10)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("6571075494204656015", 10)).shiftLeft(64)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("12714171422618877016", 10)).shiftLeft(128)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("1309675183017776880", 10)).shiftLeft(192))); |
||||||
|
assertThat(before.toMontgomery()).isEqualTo(expected); |
||||||
|
} |
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testToMont3() {
|
||||||
|
// Element before =
|
||||||
|
// new Element(
|
||||||
|
// UInt256.valueOf(new BigInteger("6121572481584493354", 10))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("12601925224297426022", 10)).shiftLeft(64))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("7716030069200636218", 10)).shiftLeft(128))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("1351674413095362254",
|
||||||
|
// 10)).shiftLeft(192)));
|
||||||
|
// Element expected =
|
||||||
|
// new Element(
|
||||||
|
// UInt256.valueOf(new BigInteger("479530773443910689", 10))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("6571075494204656015", 10)).shiftLeft(64))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("12714171422618877016", 10)).shiftLeft(128))
|
||||||
|
// .add(UInt256.valueOf(new BigInteger("1309675183017776880",
|
||||||
|
// 10)).shiftLeft(192)));
|
||||||
|
// assertThat(before.toMontgomery()).isEqualTo(expected);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetBytes() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0000000000000000000000000000000100000000000000000de04b58e8220132")); |
||||||
|
Element expected = |
||||||
|
new Element( |
||||||
|
UInt256.valueOf(new BigInteger("999881962499998002", 10)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(64)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("1", 10)).shiftLeft(128)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(192))); |
||||||
|
assertThat(x).isEqualTo(expected); |
||||||
|
Element result = x.toMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"122ce6a3d6eb56f0b071cf8bda9efc585b312658d057c98f06a7a2b2a1fe1c21")); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,199 @@ |
|||||||
|
/* |
||||||
|
* Copyright Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.verkletrie.bandersnatch.fr; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class ElementTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testIsZero() { |
||||||
|
assertThat(Element.ZERO.isZero()).isTrue(); |
||||||
|
assertThat(Element.ONE.isZero()).isFalse(); |
||||||
|
assertThat(new Element(UInt256.valueOf(42L)).isZero()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverseZero() { |
||||||
|
Element elt = Element.ZERO; |
||||||
|
assertThat(elt.inverse()).isEqualTo(elt); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverse42() { |
||||||
|
assertThat(new Element(UInt256.valueOf(42L)).inverse()) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"2546c9a92adbd3384fa236bec5cec2a385f743ac23217035cd355920b19e79b"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testInverseOverQ() { |
||||||
|
assertThat(new Element(Element.Q_MODULUS.value.add(1)).inverse()) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0ae793ddb14aec7daa9e6daec0055cea40fa7ca27fecb938dbb4f5d658db47cb"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testRandom() { |
||||||
|
assertThat(Element.random().value.lessOrEqualThan(Element.Q_MODULUS.value)).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDivide() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d433339d80809a1d80253bda402fffe5bfcfffffffefffffff3")); |
||||||
|
Element y = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d753339d80809a1d7d553bda402fffe5c1cfffffffeffffffe9")); |
||||||
|
assertThat(x.divide(y)) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"14d7b4f7f22fb5688cab25906b04691b468a5397997285ab6ef862deae100957"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testMultiply() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d433339d80809a1d80253bda402fffe5bfcfffffffefffffff3")); |
||||||
|
Element y = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d753339d80809a1d7d553bda402fffe5c1cfffffffeffffffe9")); |
||||||
|
assertThat(x.multiply(y)) |
||||||
|
.isEqualTo( |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"209ee057659143a392a0e135c23c3dee1f96f11ebf6151699193e4a29141e0fd"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNeg() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001")); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"1cfb69d4ca675f520cce760202687600ff8f87007419047174fd06b52876e7e0")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegOverQ() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"a90dc281a0c9e209d9949df9f8c69dfbabd1e2fd741aa87274fd06b62876e7df")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegZero() { |
||||||
|
Element x = Element.ZERO; |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value).isEqualTo(Element.ZERO.value); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNegOne() { |
||||||
|
Element x = new Element(UInt256.ONE); |
||||||
|
Element result = x.neg(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0x1cfb69d4ca675f520cce760202687600ff8f87007419047174fd06b52876e7e0")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testFromMont() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.fromMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"029dcd39374fa1ed499348e004ce8e397648170983b64e150042fce1ccb70b7d")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testToMont() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002")); |
||||||
|
Element result = x.toMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"ff2df0939978a11eb3730340bb816b35def26d563fd67125f62b5942d4903e8")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testToMont2() { |
||||||
|
Element before = |
||||||
|
new Element( |
||||||
|
UInt256.valueOf(new BigInteger("999881962499998002", 10)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(64)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("1", 10)).shiftLeft(128)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(192))); |
||||||
|
Element expected = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"12c21cb79c889ece6b14d87776efc93aaee3083940486c6654f431bd0fa6732a")); |
||||||
|
assertThat(before.toMontgomery()).isEqualTo(expected); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSetBytes() { |
||||||
|
Element x = |
||||||
|
new Element( |
||||||
|
UInt256.fromHexString( |
||||||
|
"0000000000000000000000000000000100000000000000000de04b58e8220132")); |
||||||
|
Element expected = |
||||||
|
new Element( |
||||||
|
UInt256.valueOf(new BigInteger("999881962499998002", 10)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(64)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("1", 10)).shiftLeft(128)) |
||||||
|
.add(UInt256.valueOf(new BigInteger("0", 10)).shiftLeft(192))); |
||||||
|
assertThat(x).isEqualTo(expected); |
||||||
|
Element result = x.toMontgomery(); |
||||||
|
assertThat(result.value) |
||||||
|
.isEqualTo( |
||||||
|
UInt256.fromHexString( |
||||||
|
"12c21cb79c889ece6b14d87776efc93aaee3083940486c6654f431bd0fa6732a")); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue