all-weather Schnorr verifier with hybrid gas strategy (Spectre/Banshee paths)
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
parent
fe9f92281b
commit
4327971456
380
src/libraries/Verifier.sol
Normal file
380
src/libraries/Verifier.sol
Normal file
@ -0,0 +1,380 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Hashes} from "./Hashes.sol";
|
||||
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
|
||||
|
||||
library Verifier {
|
||||
// Constants: https://en.bitcoin.it/wiki/Secp256k1
|
||||
uint256 internal constant N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
|
||||
uint256 internal constant P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
|
||||
uint256 internal constant GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
|
||||
uint256 internal constant GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
|
||||
uint256 internal constant EXP = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C;
|
||||
uint256 internal constant B = 7;
|
||||
|
||||
function verifyGhost(
|
||||
bytes memory call,
|
||||
uint256 px,
|
||||
uint256 rx,
|
||||
uint256 s
|
||||
) internal view returns (bool) {
|
||||
if (px >= P || rx >= P || s >= N || s == 0) { return false; }
|
||||
if (rx < N) { return verifySpectre(call, px, rx, s); }
|
||||
|
||||
(uint256 py, bool success1) = liftPoint(px);
|
||||
(uint256 ry, bool success2) = liftPoint(rx);
|
||||
if (!success1 || !success2) { return false; }
|
||||
|
||||
return verifyBanshee(call, px, py, rx, ry, s);
|
||||
}
|
||||
|
||||
function verifySpectre(
|
||||
bytes memory call,
|
||||
uint256 px,
|
||||
uint256 rx,
|
||||
uint256 s
|
||||
) internal view returns (bool) {
|
||||
uint256 e = computeChallenge(call, rx, px);
|
||||
(address convertedR, bool success) = point2Address(rx);
|
||||
if (!success) { return false; }
|
||||
|
||||
// Explanation: https://hackmd.io/@nZ-twauPRISEa6G9zg3XRw/SyjJzSLt9
|
||||
bytes32 sp = bytes32(N - mulmod(s, px, N));
|
||||
bytes32 ep = bytes32(N - mulmod(e, px, N));
|
||||
|
||||
// Parity should be always even
|
||||
address recoveredR = ecrecover(sp, 27, bytes32(px), ep);
|
||||
return recoveredR == convertedR;
|
||||
}
|
||||
|
||||
function verifyBanshee(
|
||||
bytes memory call,
|
||||
uint256 px,
|
||||
uint256 py,
|
||||
uint256 rx,
|
||||
uint256 ry,
|
||||
uint256 s
|
||||
) internal pure returns (bool) {
|
||||
// TODO: because I lift it before, do I need to check is it on curve?
|
||||
// both of them Px,Py and Rx,Ry
|
||||
if (!isOnCurve(rx, ry) || !isOnCurve(px, py)) { return false; }
|
||||
|
||||
uint256 e = computeChallenge(call, rx, px);
|
||||
if (e == 0) return false; // Cheap and safe
|
||||
|
||||
// s ⋅ G = R + hash(R || m) ⋅ Y
|
||||
// R = s ⋅ G + hash(R || m) ⋅ Y
|
||||
(uint256 x, uint256 y, uint256 z) = multiScalarMulAdd(GX, GY, s, px, py, N - e);
|
||||
(x, y) = toAffine(x, y, z);
|
||||
|
||||
if (!isOnCurve(x, y)) return false;
|
||||
return x == rx && y == ry;
|
||||
}
|
||||
|
||||
function point2Address(uint256 rx) internal view returns (address, bool) {
|
||||
(uint256 ry, bool success) = liftPoint(rx);
|
||||
if (!success) { return (address(0), false); }
|
||||
|
||||
bytes32 encodedR = Hashes.efficientKeccak256(rx, ry);
|
||||
address addressR = address(uint160(uint256(encodedR)));
|
||||
return (addressR, true);
|
||||
}
|
||||
|
||||
function liftPoint(uint256 x) internal view returns (uint256, bool) {
|
||||
if (x >= P) { return (0, false); }
|
||||
|
||||
// y^2 = x^3 + 7 (mod P)
|
||||
uint256 y2 = addmod(mulmod(x, mulmod(x, x, P), P), B, P);
|
||||
y2 = expModPrecompile(y2);
|
||||
|
||||
uint256 y = (y2 & 1) == 0 ? y2 : P - y2; // BIP-340: point is always even
|
||||
if (!isOnCurve(x, y)) { return (0, false); } // point does not exist on curve
|
||||
|
||||
return (y, true);
|
||||
}
|
||||
|
||||
function expModPrecompile(uint256 base) internal view returns (uint256 result) {
|
||||
uint256 localEXP = EXP;
|
||||
uint256 localP = P;
|
||||
|
||||
assembly {
|
||||
let pointer := mload(0x40)
|
||||
|
||||
mstore(pointer, 0x20)
|
||||
mstore(add(pointer, 0x20), 0x20)
|
||||
mstore(add(pointer, 0x40), 0x20)
|
||||
|
||||
mstore(add(pointer, 0x60), base)
|
||||
mstore(add(pointer, 0x80), localEXP)
|
||||
mstore(add(pointer, 0xa0), localP)
|
||||
|
||||
// Modular Exponentiation Precompile (modexp)
|
||||
let success := staticcall(gas(), 0x05, pointer, 0xc0, pointer, 0x20)
|
||||
if iszero(success) { revert(0, 0) }
|
||||
|
||||
result := mload(pointer)
|
||||
}
|
||||
}
|
||||
|
||||
function computeChallenge(bytes memory call, uint256 rx, uint256 px) internal pure returns (uint256) {
|
||||
// Precomputed `sha256("BIP0340/challenge")`
|
||||
bytes32 tag = 0x7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c;
|
||||
return uint256(sha256(abi.encodePacked(tag, tag, rx, px, call))) % N;
|
||||
}
|
||||
|
||||
function findMaxBitLength(uint256 k1, uint256 k2) internal pure returns (uint256 bits) {
|
||||
assembly {
|
||||
// Find maximum of the three scalars
|
||||
let max := k1
|
||||
if gt(k2, max) { max := k2 }
|
||||
|
||||
// if (v >> 128 != 0) { v >>= 128; bits += 128; }
|
||||
if gt(max, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
|
||||
max := shr(128, max)
|
||||
bits := 128
|
||||
}
|
||||
// if (v >> 64 != 0) { v >>= 64; bits += 64; }
|
||||
if gt(max, 0xFFFFFFFFFFFFFFFF) {
|
||||
max := shr(64, max)
|
||||
bits := add(bits, 64)
|
||||
}
|
||||
// if (v >> 32 != 0) { v >>= 32; bits += 32; }
|
||||
if gt(max, 0xFFFFFFFF) {
|
||||
max := shr(32, max)
|
||||
bits := add(bits, 32)
|
||||
}
|
||||
// if (v >> 16 != 0) { v >>= 16; bits += 16; }
|
||||
if gt(max, 0xFFFF) {
|
||||
max := shr(16, max)
|
||||
bits := add(bits, 16)
|
||||
}
|
||||
// if (v >> 8 != 0) { v >>= 8; bits += 8; }
|
||||
if gt(max, 0xFF) {
|
||||
max := shr(8, max)
|
||||
bits := add(bits, 8)
|
||||
}
|
||||
// if (v >> 4 != 0) { v >>= 4; bits += 4; }
|
||||
if gt(max, 0xF) {
|
||||
max := shr(4, max)
|
||||
bits := add(bits, 4)
|
||||
}
|
||||
// if (v >> 2 != 0) { v >>= 2; bits += 2; }
|
||||
if gt(max, 0x3) {
|
||||
max := shr(2, max)
|
||||
bits := add(bits, 2)
|
||||
}
|
||||
// if (v >> 1 != 0) { /* v >>= 1; */ bits += 1; }
|
||||
if gt(max, 0x1) {
|
||||
bits := add(bits, 1)
|
||||
}
|
||||
bits := add(bits, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function toAffine(uint256 x, uint256 y, uint256 z) internal pure returns (uint256, uint256) {
|
||||
if (z == 0) return (0, 0); // Identity point
|
||||
uint256 t0;
|
||||
assembly {
|
||||
// Extended Euclidean algorithm (iterative, assembly)
|
||||
// Typically lower average gas than the modexp precompile for single inversions,
|
||||
// but execution time (and gas) depends on input values — not constant-time.
|
||||
|
||||
let t1 := 1
|
||||
let r0 := P
|
||||
let r1 := z
|
||||
|
||||
for {} r1 {} {
|
||||
let q := div(r0, r1)
|
||||
|
||||
// t0, t1 = t1, t0 - q * t1
|
||||
let t1_new := sub(t0, mul(q, t1))
|
||||
t0 := t1
|
||||
t1 := t1_new
|
||||
|
||||
// r0, r1 = r1, r0 - q * r1
|
||||
let r1_new := sub(r0, mul(q, r1))
|
||||
r0 := r1
|
||||
r1 := r1_new
|
||||
}
|
||||
|
||||
if slt(t0, 0) {
|
||||
t0 := add(t0, P)
|
||||
}
|
||||
}
|
||||
|
||||
return (mulmod(x, t0, P), mulmod(y, t0, P));
|
||||
}
|
||||
|
||||
function isOnCurve(uint256 x, uint256 y) internal pure returns (bool) {
|
||||
if (x >= P || y >= P) return false;
|
||||
if (x == 0 && y == 0) return false; // Identity point
|
||||
|
||||
uint lhs = mulmod(y, y, P); // y^2
|
||||
uint rhs = mulmod(mulmod(x, x, P), x, P); // x^3
|
||||
rhs = addmod(rhs, B, P); // x^3 + 7
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
function multiScalarMulAdd(
|
||||
uint256 x1, uint256 y1, uint256 k1,
|
||||
uint256 x2, uint256 y2, uint256 k2
|
||||
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
|
||||
// Implementation of the Straus-Shamir trick described in
|
||||
// Trading Inversions for Multiplications in Elliptic Curve Cryptography.
|
||||
// (https://eprint.iacr.org/2003/257.pdf Page 7).
|
||||
|
||||
uint256 bits = findMaxBitLength(k1, k2);
|
||||
|
||||
uint256[4] memory precomputedXs;
|
||||
uint256[4] memory precomputedYs;
|
||||
uint256[4] memory precomputedZs;
|
||||
|
||||
precomputedXs[1] = x2; precomputedYs[1] = y2; precomputedZs[1] = 1; // 01: P2
|
||||
precomputedXs[2] = x1; precomputedYs[2] = y1; precomputedZs[2] = 1; // 10: P1
|
||||
(precomputedXs[3], precomputedYs[3], precomputedZs[3]) = projectiveAdd(x1, y1, 1, x2, y2, 1); // 11: P1+P2
|
||||
|
||||
y3 = 1;
|
||||
|
||||
for (; bits > 0;) {
|
||||
unchecked { --bits; }
|
||||
(x3, y3, z3) = projectiveDouble(x3, y3, z3);
|
||||
|
||||
uint8 mask;
|
||||
assembly {
|
||||
mask := or(
|
||||
shl(1, and(shr(bits, k1), 1)),
|
||||
and(shr(bits, k2), 1)
|
||||
)
|
||||
}
|
||||
|
||||
if (mask == 0) { continue; }
|
||||
|
||||
if (mask == 3) {
|
||||
(x3, y3, z3) = projectiveAdd(
|
||||
x3, y3, z3, precomputedXs[mask], precomputedYs[mask], precomputedZs[mask]
|
||||
);
|
||||
} else {
|
||||
(x3, y3, z3) = projectiveAddMixed(
|
||||
x3, y3, z3, precomputedXs[mask], precomputedYs[mask]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function projectiveDouble(
|
||||
uint256 x,
|
||||
uint256 y,
|
||||
uint256 z
|
||||
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
|
||||
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 9).
|
||||
|
||||
// X3 = 2XY (Y^2 − 9bZ^2), (ok)
|
||||
// Y3 = (Y^2 − 9bZ^2)(Y^2 + 3bZ^2) + 24bY^2Z^2,
|
||||
// Z3 = 8Y^3Z
|
||||
|
||||
assembly {
|
||||
let t0 := mulmod(y, y, P) // t0 = y²
|
||||
z3 := mulmod(8, t0, P) // z3 = 8y²
|
||||
let t1 := mulmod(y, z, P) // t1 = y·z
|
||||
let t2 := mulmod(z, z, P) // t2 = z²
|
||||
t2 := mulmod(21, t2, P) // t2 = 3b·z² (b=7 → 3b=21)
|
||||
x3 := mulmod(t2, z3, P) // x3 = (3b·z²)(8y²) = 24b·y²·z²
|
||||
y3 := addmod(t0, t2, P) // y3 = y² + 3b·z²
|
||||
z3 := mulmod(t1, z3, P) // z3 = (y·z)(8y²) = 8y³·z
|
||||
t1 := addmod(t0, sub(P, mulmod(3, t2, P)), P) // t1 = y² − 9b·z²
|
||||
y3 := addmod(x3, mulmod(t1, y3, P), P) // y3 = 24b·y²·z² + (y²−9b·z²)(y²+3b·z²)
|
||||
x3 := mulmod(t1, mulmod(x, y, P), P) // x3 = (y²−9b·z²)·x·y
|
||||
x3 := addmod(x3, x3, P) // x3 = 2xy·(y²−9b·z²)
|
||||
}
|
||||
}
|
||||
|
||||
function projectiveAdd(
|
||||
uint256 x1, uint256 y1, uint256 z1,
|
||||
uint256 x2, uint256 y2,uint256 z2
|
||||
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
|
||||
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 7).
|
||||
|
||||
// X3 = (X1Y2 + X2Y1)(Y1Y2 − 3bZ1Z2) − 3b(Y1Z2 + Y2Z1)(X1Z2 + X2Z1),
|
||||
// Y3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 − 3bZ1Z2) + 9bX1X2(X1Z2 + X2Z1),
|
||||
// Z3 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2) + 3X1X2(X1Y2 + X2Y1),
|
||||
|
||||
assembly {
|
||||
let t0 := mulmod(x1, x2, P) // 1. t0 ← X1 · X2 => (X1·X2)
|
||||
let t1 := mulmod(y1, y2, P) // 2. t1 ← Y1 · Y2 => (Y1·Y2)
|
||||
let t2 := mulmod(z1, z2, P) // 3. t2 ← Z1 · Z2 => (Z1·Z2)
|
||||
let t3 := addmod(x1, y1, P) // 4. t3 ← X1 + Y1 => (X1 + Y1)
|
||||
let t4 := addmod(x2, y2, P) // 5. t4 ← X2 + Y2 => (X2 + Y2)
|
||||
t3 := mulmod(t3, t4, P) // 6. t3 ← t3 · t4 => ((X1 + Y1) · (X2 + Y2))
|
||||
t4 := addmod(t0, t1, P) // 7. t4 ← t0 + t1 => (X1·X2 + Y1·Y2)
|
||||
t3 := addmod(t3, sub(P, t4), P) // 8. t3 ← t3 - t4 => ((X1 + Y1)·(X2 + Y2) - X1·X2 - Y1·Y2)
|
||||
t4 := addmod(y1, z1, P) // 9. t4 ← Y1 + Z1 => (Y1 + Z1)
|
||||
x3 := addmod(y2, z2, P) // 10. X3 ← Y2 + Z2 => (Y2 + Z2)
|
||||
t4 := mulmod(t4, x3, P) // 11. t4 ← t4 · X3 => ((Y1 + Z1) · (Y2 + Z2))
|
||||
x3 := addmod(t1, t2, P) // 12. X3 ← t1 + t2 => (Y1·Y2 + Z1·Z2)
|
||||
t4 := addmod(t4, sub(P, x3), P) // 13. t4 ← t4 - X3 => ((Y1 + Z1)·(Y2 + Z2) - Y1·Y2 - Z1·Z2)
|
||||
x3 := addmod(x1, z1, P) // 14. X3 ← X1 + Z1 => (X1 + Z1)
|
||||
y3 := addmod(x2, z2, P) // 15. Y3 ← X2 + Z2 => (X2 + Z2)
|
||||
x3 := mulmod(x3, y3, P) // 16. X3 ← X3 · Y3 => ((X1 + Z1) · (X2 + Z2))
|
||||
y3 := addmod(t0, t2, P) // 17. Y3 ← t0 + t2 => (X1·X2 + Z1·Z2)
|
||||
y3 := addmod(x3, sub(P, y3), P) // 18. Y3 ← X3 - Y3 => ((X1 + Z1)·(X2 + Z2) - X1·X2 - Z1·Z2)
|
||||
x3 := addmod(t0, t0, P) // 19. X3 ← t0 + t0 => (2·X1·X2)
|
||||
t0 := addmod(x3, t0, P) // 20. t0 ← X3 + t0 => (3·X1·X2)
|
||||
t2 := mulmod(21, t2, P) // 21. t2 ← B3 · t2 => 3b · Z1·Z2
|
||||
z3 := addmod(t1, t2, P) // 22. Z3 ← t1 + t2 => Y1·Y2 + 3·b·Z1·Z2
|
||||
t1 := addmod(t1, sub(P, t2), P) // 23. t1 ← t1 - t2 => Y1·Y2 - 3·b·Z1·Z2
|
||||
y3 := mulmod(21, y3, P) // 24. Y3 ← B3 · Y3 => 3b · ((X1+Z1)(X2+Z2) - X1·X2 - Z1·Z2)
|
||||
x3 := mulmod(t4, y3, P) // 25. X3 ← t4 · Y3 => 3b·((Y1+Z1)(Y2+Z2)-Y1·Y2-Z1·Z2) · ((X1+Z1)(X2+Z2)-X1·X2-Z1·Z2)
|
||||
t2 := mulmod(t3, t1, P) // 26. t2 ← t3 · t1 => ((X1+Y1)(X2+Y2)-X1·X2-Y1·Y2) · (Y1·Y2 - 3·b·Z1·Z2)
|
||||
x3 := addmod(t2, sub(P, x3), P) // 27. X3 ← t2 - X3 => (X1Y2+X2Y1)(Y1·Y2-3·b·Z1·Z2) - 3b(Y1·Z2+Y2·Z1)(X1·Z2+X2·Z1)
|
||||
y3 := mulmod(y3, t0, P) // 28. Y3 ← Y3 · t0 => 3·b·((X1+Z1)(X2+Z2) - X1·X2 - Z1·Z2) · 3·X1·X2 = 9·b·X1·X2·(X1·Z2+X2·Z1)
|
||||
t1 := mulmod(t1, z3, P) // 29. t1 ← t1 · Z3 => (Y1·Y2-3·b·Z1·Z2) · (Y1·Y2+3·b·Z1·Z2)
|
||||
y3 := addmod(t1, y3, P) // 30. Y3 ← t1 + Y3 => (Y1Y2+3·b·Z1·Z2)(Y1·Y2-3·b·Z1·Z2) + 9b·X1·X2·(X1·Z2+X2·Z1)
|
||||
t0 := mulmod(t0, t3, P) // 31. t0 ← t0 · t3 => (3·X1·X2) · ((X1+Y1)(X2+Y2)-X1·X2-Y1·Y2)
|
||||
z3 := mulmod(z3, t4, P) // 32. Z3 ← Z3 · t4 => (Y1·Y2+3·b·Z1·Z2) · ((Y1+Z1)(Y2+Z2)-Y1·Y2-Z1·Z2)
|
||||
z3 := addmod(z3, t0, P) // 33. Z3 ← Z3 + t0 => (Y1·Z2+Y2·Z1)·(Y1·Y2+3·b·Z1·Z2) + 3·X1·X2·(X1·Y2+X2·Y1)
|
||||
}
|
||||
}
|
||||
|
||||
function projectiveAddMixed(
|
||||
uint256 x1, uint256 y1, uint256 z1,
|
||||
uint256 x2, uint256 y2
|
||||
) internal pure returns (uint256 x3, uint256 y3, uint256 z3) {
|
||||
// Implementation of the complete addition formula from Renes-Costello-Batina 2015
|
||||
// (https://eprint.iacr.org/2015/1060 Algorithm 8).
|
||||
|
||||
// X3 = (X1Y2 + X2Y1)(Y1Y2 − 3bZ1) − 3b(Y1 + Y2Z1)(X1 + X2Z1),
|
||||
// Y3 = (Y1Y2 + 3bZ1)(Y1Y2 − 3bZ1) + 9bX1X2(X1 + X2Z1),
|
||||
// Z3 = (Y1 + Y2Z1)(Y1Y2 + 3bZ1) + 3X1X2(X1Y2 + X2Y1),
|
||||
|
||||
assembly {
|
||||
let t0 := mulmod(x1, x2, P) // 1. t0 ← X1 · X2 => (X1·X2)
|
||||
let t1 := mulmod(y1, y2, P) // 2. t1 ← Y1 · Y2 => (Y1·Y2)
|
||||
let t3 := mulmod(x2, y1, P) // 3. t3 ← X2 + Y2 => (X2·Y1)
|
||||
let t4 := mulmod(x1, y2, P) // 4. t4 ← X1 + Y1 => (X1·Y2)
|
||||
t3 := addmod(t3, t4, P) // 5. t3 ← t3 − t4 => (X2·Y1 + X1·Y2)
|
||||
t4 := mulmod(y2, z1, P) // 6. t4 ← Y2 · Z1 => (Y2·Z1)
|
||||
t4 := addmod(t4, y1, P) // 7. t4 ← t4 + Y1 => (Y2·Z1 + Y1)
|
||||
y3 := mulmod(x2, z1, P) // 8. Y3 ← X2 · Z1 => (X2·Z1)
|
||||
y3 := addmod(y3, x1, P) // 9. Y3 ← Y3 + X1 => (X2·Z1 + X1)
|
||||
t0 := mulmod(3, t0, P) // 10. t0 ← X3 + t0 => (3·(X1·X2))
|
||||
let t2 := mulmod(21, z1, P) // 11. t2 ← b3 · Z1 => (b3·Z1)
|
||||
z3 := addmod(t1, t2, P) // 12. Z3 ← t1 + t2 => (Y1·Y2 + b·3·Z1)
|
||||
t1 := addmod(t1, sub(P, t2), P) // 13. t1 ← t1 − t2 => (Y1·Y2 - b·3·Z1)
|
||||
y3 := mulmod(21, y3, P) // 14. Y3 ← b3 · Y3 => 3·b·(X2·Z1 + X1)
|
||||
x3 := mulmod(t4, y3, P) // 15. X3 ← t4 · Y3 => (Y2·Z1 + Y1)·b·3·(X2·Z1 + X1)
|
||||
t2 := mulmod(t3, t1, P) // 16. t2 ← t3 · t1 => ((X2·Y1 + X1·Y2)·(Y1·Y2 - b3·Z1))
|
||||
x3 := addmod(t2, sub(P, x3), P) // 17. X3 ← t2 − X3 => ((X2·Y1 + X1·Y2)·(Y1·Y2 - b3·Z1) - 3·B·(Y2·Z1 + Y1)·(X2·Z1 + X1))
|
||||
y3 := mulmod(y3, t0, P) // 18. Y3 ← Y3 · t0 => (9·b·(X2·Z1 + X1)·X1·X2)
|
||||
t1 := mulmod(t1, z3, P) // 19. t1 ← t1 · Z3 => (Y1·Y2 - b·3·Z1)·(Y1·Y2 + b·3·Z1)
|
||||
y3 := addmod(t1, y3, P) // 20. Y3 ← t1 + Y3 => ((Y1·Y2 - b·3·Z1)·(Y1·Y2 + 3·b·Z1) + 9·b·(X2·Z1 + X1)·X1·X2)
|
||||
t0 := mulmod(t0, t3, P) // 21. t0 ← t0 · t3 => (3·X2·Y1 + (X2·Y1 + X1·Y2))
|
||||
z3 := mulmod(z3, t4, P) // 22. Z3 ← Z3 · t4 => (Y1·Y2 + b·3·Z1)·(Y2·Z1 + Y1)
|
||||
z3 := addmod(z3, t0, P) // 23. Z3 ← Z3 + t0 => ((Y1·Y2 + b·3·Z1)·(Y2·Z1 + Y1) + 3·X2·Y1·(X2·Y1 + X1·Y2))
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user