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
Antoine Toulme 2 years ago committed by GitHub
parent 9006445147
commit f9bc1b76e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 56
      ethereum/verkletrie/build.gradle
  2. 55
      ethereum/verkletrie/src/main/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/Point.java
  3. 32
      ethereum/verkletrie/src/main/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/PointAffine.java
  4. 526
      ethereum/verkletrie/src/main/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/Element.java
  5. 508
      ethereum/verkletrie/src/main/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/Element.java
  6. 220
      ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fp/ElementTest.java
  7. 199
      ethereum/verkletrie/src/test/java/org/hyperledger/besu/ethereum/verkletrie/bandersnatch/fr/ElementTest.java
  8. 71
      gradle/verification-metadata.xml
  9. 1
      gradle/versions.gradle
  10. 1
      settings.gradle

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

@ -317,6 +317,22 @@
<sha256 value="5026062f36c6ad718dae4f024d1cd89f98df3146dc1e8cf2e4c2bcbf978185be" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.dataformat" name="jackson-dataformat-yaml" version="2.13.4">
<artifact name="jackson-dataformat-yaml-2.13.4.jar">
<sha256 value="f2992595378c0dd81c317afa788e06dcb5ef24e1c825191251818f5c892ed3c5" origin="Generated by Gradle"/>
</artifact>
<artifact name="jackson-dataformat-yaml-2.13.4.module">
<sha256 value="ec19f0ee966041f6e525807f696b1f030297cb62c8acd0f35b2c0289fe25a6fe" origin="Generated by Gradle"/>
</artifact>
<artifact name="jackson-dataformat-yaml-2.13.4.pom">
<sha256 value="fa117aa8e4198ba2c66d7d79c89aa3f4495c7abb41e25a9190c4d5f55e1c57e2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.dataformat" name="jackson-dataformats-text" version="2.13.4">
<artifact name="jackson-dataformats-text-2.13.4.pom">
<sha256 value="ab93d380ec64ba6632775446cf2428aa755d905e11cf8cb02ec04989aab8b6d5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.datatype" name="jackson-datatype-jdk8" version="2.11.0">
<artifact name="jackson-datatype-jdk8-2.11.0.pom">
<sha256 value="873fdf685cb31ee03b419972f3c4ad5ddb03c3186d5b7c6405792699af9d305d" origin="Generated by Gradle"/>
@ -4019,6 +4035,17 @@
<sha256 value="125ed16e300f225a36c5b64c5d24b6d01d7dd607a16ba906aac563d9f1584183" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="blake2bf" version="0.6.1">
<artifact name="blake2bf-0.6.1.jar">
<sha256 value="809715f55a410fe6da444eacecd26f7065414c3ed40988b956c20b3a8e11abe2" origin="Generated by Gradle"/>
</artifact>
<artifact name="blake2bf-0.6.1.module">
<sha256 value="e1e33b9398e192aa886ee4daee145e7c13359011e115fb7e3f4cb208546d1c23" origin="Generated by Gradle"/>
</artifact>
<artifact name="blake2bf-0.6.1.pom">
<sha256 value="c59f7a81e169b9099d5da38c346b69b93e84a5ace7ab3a9d17d042929ed42614" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="blake2bf" version="0.7.1">
<artifact name="blake2bf-0.7.1.jar">
<sha256 value="e06429773d69d6fe5006ef7d7c45f11c2df56dc69f00a15e29519f17cc53754e" origin="Generated by Gradle"/>
@ -4030,6 +4057,17 @@
<sha256 value="58d501993a559e26cfab9151abcd52636386bd26029c84541c7f5f52e063f580" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="bls12-381" version="0.6.1">
<artifact name="bls12-381-0.6.1.jar">
<sha256 value="b2a6d139a7d13e453272aa68ad448989c4651d69c0e24cd1632f76a3cdfad0ee" origin="Generated by Gradle"/>
</artifact>
<artifact name="bls12-381-0.6.1.module">
<sha256 value="281ab4d15d0e5a39dd63520c84c39c14e6a8d2eb75abe3da3e6d6fd01e3dfda2" origin="Generated by Gradle"/>
</artifact>
<artifact name="bls12-381-0.6.1.pom">
<sha256 value="8cecb17d0ed5de8ab1059b8aee8da2928272e5601185f1a19a42b080b5724026" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="bls12-381" version="0.7.1">
<artifact name="bls12-381-0.7.1.jar">
<sha256 value="bf116b267489302805cf0b89f07cde139f1ab41089336cf0779dd269463b2acb" origin="Generated by Gradle"/>
@ -4041,6 +4079,28 @@
<sha256 value="eb939df4f6ad29183c8f216e193a8aa83690b3e6314ed9f5627c9f9e8b9dd762" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="ipa-multipoint" version="0.7.1">
<artifact name="ipa-multipoint-0.7.1.jar">
<sha256 value="6f0231fd8163f934ac38569bebd5fa963e7d84a3629a82049134a259075410f8" origin="Generated by Gradle"/>
</artifact>
<artifact name="ipa-multipoint-0.7.1.module">
<sha256 value="13030f65ec95bf8d1414ab2fd962193f65aebaabe7f3c035d2460615c6c585e7" origin="Generated by Gradle"/>
</artifact>
<artifact name="ipa-multipoint-0.7.1.pom">
<sha256 value="736c81314a55fa16e856885c8357ff6cbee003b529142b6dd8aa6c4555332146" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256k1" version="0.6.1">
<artifact name="secp256k1-0.6.1.jar">
<sha256 value="c12e0ed581a727240bd16c67e137ee30ca1cda2a55238e58e745378a6159478e" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256k1-0.6.1.module">
<sha256 value="93fa3b93096072e3934b5e0f9d863405c57158461c5d303dbc1978090613c865" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256k1-0.6.1.pom">
<sha256 value="f322921a5ef98b9012c6d4f83611bd8e5f56f3e26b26d3750179f1f47b153a72" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256k1" version="0.7.1">
<artifact name="secp256k1-0.7.1.jar">
<sha256 value="80e5650d89099976c7932b4dfdfba0e09ecdd1650cdf0d27f45b9ade8e5ee71f" origin="Generated by Gradle"/>
@ -4052,6 +4112,17 @@
<sha256 value="f1685ec3024a025df9a87c36936fc607915f2178586aa8e5cea2f572920836c1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256r1" version="0.6.1">
<artifact name="secp256r1-0.6.1.jar">
<sha256 value="f0af26c128616a65616df3419bafeb14675079f3bbda12dfea829e37ab831e10" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256r1-0.6.1.module">
<sha256 value="399ea9bc9cfa7bd9ef95e8b8c3fff9839be61e3a3b4fe2fe4daa6d392aa7538c" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256r1-0.6.1.pom">
<sha256 value="81017f26ffedf193875f64f6850d16b09e730dd43bf236360fbc97bc44dee722" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256r1" version="0.7.1">
<artifact name="secp256r1-0.7.1.jar">
<sha256 value="520f2d2b8d97ab070af317a740fb5be3c052b04c177e96779e46b0a8502aa35a" origin="Generated by Gradle"/>

@ -155,6 +155,7 @@ dependencyManagement {
dependencySet(group: 'org.hyperledger.besu', version: '0.7.1') {
entry 'arithmetic'
entry 'ipa-multipoint'
entry 'bls12-381'
entry 'secp256k1'
entry 'secp256r1'

@ -65,6 +65,7 @@ include 'ethereum:rlp'
include 'ethereum:stratum'
include 'ethereum:ethstats'
include 'ethereum:trie'
include 'ethereum:verkletrie'
include 'evm'
include 'metrics:core'
include 'metrics:rocksdb'

Loading…
Cancel
Save