├── .gitattributes ├── .gitignore ├── README.md ├── contracts ├── CurveBabyJubJub.sol ├── CurveBabyJubJubExtended.sol ├── CurveBabyJubJubHelper.sol └── Migrations.sol ├── migrations └── 1_initial_migration.js ├── test ├── CurveBabyJubJub.js ├── TestCurveBabyJubJub.sol └── TestCurveBabyJubJubExtended.sol └── truffle-config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sol-baby-jubjub 2 | 3 | Currently a rough attempt at implementing the [baby jubjub](https://github.com/barryWhiteHat/baby_jubjub) curve in Solidity. Primarily based off the Python implementation which can be found [here](https://github.com/barryWhiteHat/baby_jubjub_ecc/blob/620dbb661a8a24b29eb92fd488201b988609db9e/tests/sapling_jubjub.py). -------------------------------------------------------------------------------- /contracts/CurveBabyJubJub.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | library CurveBabyJubJub { 5 | // Curve parameters 6 | // E: 168700x^2 + y^2 = 1 + 168696x^2y^2 7 | // A = 168700 8 | uint256 public constant A = 0x292FC; 9 | // D = 168696 10 | uint256 public constant D = 0x292F8; 11 | // Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 12 | uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001; 13 | 14 | /** 15 | * @dev Add 2 points on baby jubjub curve 16 | * Formulae for adding 2 points on a twisted Edwards curve: 17 | * x3 = (x1y2 + y1x2) / (1 + dx1x2y1y2) 18 | * y3 = (y1y2 - ax1x2) / (1 - dx1x2y1y2) 19 | */ 20 | function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) internal view returns (uint256 x3, uint256 y3) { 21 | if (_x1 == 0 && _y1 == 0) { 22 | return (_x2, _y2); 23 | } 24 | 25 | if (_x2 == 0 && _y1 == 0) { 26 | return (_x1, _y1); 27 | } 28 | 29 | uint256 x1x2 = mulmod(_x1, _x2, Q); 30 | uint256 y1y2 = mulmod(_y1, _y2, Q); 31 | uint256 dx1x2y1y2 = mulmod(D, mulmod(x1x2, y1y2, Q), Q); 32 | uint256 x3Num = addmod(mulmod(_x1, _y2, Q), mulmod(_y1, _x2, Q), Q); 33 | uint256 y3Num = submod(y1y2, mulmod(A, x1x2, Q), Q); 34 | 35 | x3 = mulmod(x3Num, inverse(addmod(1, dx1x2y1y2, Q)), Q); 36 | y3 = mulmod(y3Num, inverse(submod(1, dx1x2y1y2, Q)), Q); 37 | } 38 | 39 | /** 40 | * @dev Double a point on baby jubjub curve 41 | * Doubling can be performed with the same formula as addition 42 | */ 43 | function pointDouble(uint256 _x1, uint256 _y1) internal view returns (uint256 x2, uint256 y2) { 44 | return pointAdd(_x1, _y1, _x1, _y1); 45 | } 46 | 47 | /** 48 | * @dev Multiply a point on baby jubjub curve by a scalar 49 | * Use the double and add algorithm 50 | */ 51 | function pointMul(uint256 _x1, uint256 _y1, uint256 _d) internal view returns (uint256 x2, uint256 y2) { 52 | uint256 remaining = _d; 53 | 54 | uint256 px = _x1; 55 | uint256 py = _y1; 56 | uint256 ax = 0; 57 | uint256 ay = 0; 58 | 59 | while (remaining != 0) { 60 | if ((remaining & 1) != 0) { 61 | // Binary digit is 1 so add 62 | (ax, ay) = pointAdd(ax, ay, px, py); 63 | } 64 | 65 | (px, py) = pointDouble(px, py); 66 | 67 | remaining = remaining / 2; 68 | } 69 | 70 | x2 = ax; 71 | y2 = ay; 72 | } 73 | 74 | /** 75 | * @dev Check if a given point is on the curve 76 | * (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0 77 | */ 78 | function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) { 79 | uint256 xSq = mulmod(_x, _x, Q); 80 | uint256 ySq = mulmod(_y, _y, Q); 81 | uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q); 82 | uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q); 83 | return submod(lhs, rhs, Q) == 0; 84 | } 85 | 86 | /** 87 | * @dev Perform modular subtraction 88 | */ 89 | function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) { 90 | uint256 aNN = _a; 91 | 92 | if (_a <= _b) { 93 | aNN += _mod; 94 | } 95 | 96 | return addmod(aNN - _b, 0, _mod); 97 | } 98 | 99 | /** 100 | * @dev Compute modular inverse of a number 101 | */ 102 | function inverse(uint256 _a) internal view returns (uint256) { 103 | // We can use Euler's theorem instead of the extended Euclidean algorithm 104 | // Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m) 105 | return expmod(_a, Q - 2, Q); 106 | } 107 | 108 | /** 109 | * @dev Helper function to call the bigModExp precompile 110 | */ 111 | function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) { 112 | assembly { 113 | let memPtr := mload(0x40) 114 | mstore(memPtr, 0x20) // Length of base _b 115 | mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e 116 | mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m 117 | mstore(add(memPtr, 0x60), _b) // Base _b 118 | mstore(add(memPtr, 0x80), _e) // Exponent _e 119 | mstore(add(memPtr, 0xa0), _m) // Modulus _m 120 | 121 | // The bigModExp precompile is at 0x05 122 | let success := staticcall(gas, 0x05, memPtr, 0xc0, memPtr, 0x20) 123 | switch success 124 | case 0 { 125 | revert(0x0, 0x0) 126 | } default { 127 | o := mload(memPtr) 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /contracts/CurveBabyJubJubExtended.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | /** 5 | * @dev Baby jubjub curve using extended twisted edwards coordinate points 6 | * Paper on extended twisted edwards coordinates: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf 7 | * Based on Python implementation: https://github.com/HarryR/ethsnarks/blob/jubjub/ethsnarks/jubjub.py 8 | */ 9 | library CurveBabyJubJubExtended { 10 | // Curve parameters 11 | // E: 168700x^2 + y^2 = 1 + 168696x^2y^2 12 | // A = 168700 13 | uint256 public constant A = 0x292FC; 14 | // D = 168696 15 | uint256 public constant D = 0x292F8; 16 | // Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 17 | uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001; 18 | 19 | /** 20 | * @dev Add 2 etec points on baby jubjub curve 21 | * x3 = (x1y2 + y1x2) * (z1z2 - dt1t2) 22 | * y3 = (y1y2 - ax1x2) * (z1z2 + dt1t2) 23 | * t3 = (y1y2 - ax1x2) * (x1y2 + y1x2) 24 | * z3 = (z1z2 - dt1t2) * (z1z2 + dt1t2) 25 | */ 26 | function pointAdd(uint256[4] _p1, uint256[4] _p2) internal pure returns (uint256[4] p3) { 27 | if (_p1[0] == 0 && _p1[1] == 0 && _p1[2] == 0 && _p1[3] == 0) { 28 | return _p2; 29 | } 30 | 31 | if (_p2[0] == 0 && _p2[1] == 0 && _p2[2] == 0 && _p2[3] == 0) { 32 | return _p1; 33 | } 34 | 35 | uint256[8] memory intermediates; 36 | // A <- x1 * x2 37 | intermediates[0] = mulmod(_p1[0], _p2[0], Q); 38 | // B <- y1 * y2 39 | intermediates[1] = mulmod(_p1[1], _p2[1], Q); 40 | // C <- d * t1 * t2 41 | intermediates[2] = mulmod(mulmod(D, _p1[2], Q), _p2[2], Q); 42 | // D <- z1 * x2 43 | intermediates[3] = mulmod(_p1[3], _p2[3], Q); 44 | // E <- (x1 + y1) * (x2 + y2) - A - B 45 | intermediates[4] = submod(submod(mulmod(addmod(_p1[0], _p1[1], Q), addmod(_p2[0], _p2[1], Q), Q), intermediates[0], Q), intermediates[1], Q); 46 | // F <- D - C 47 | intermediates[5] = submod(intermediates[3], intermediates[2], Q); 48 | // G <- D + C 49 | intermediates[6] = addmod(intermediates[3], intermediates[2], Q); 50 | // H <- B - a * A 51 | intermediates[7] = submod(intermediates[1], mulmod(A, intermediates[0], Q), Q); 52 | 53 | // x3 54 | p3[0] = mulmod(intermediates[4], intermediates[5], Q); 55 | // y3 56 | p3[1] = mulmod(intermediates[6], intermediates[7], Q); 57 | // t3 58 | p3[2] = mulmod(intermediates[4], intermediates[7], Q); 59 | // z3 60 | p3[3] = mulmod(intermediates[5], intermediates[6], Q); 61 | } 62 | 63 | /** 64 | * @dev Add 2 etec points on baby jubjub curve 65 | * x3 = (x1y2 + y1x2) * (z1z2 - dt1t2) 66 | * y3 = (y1y2 - ax1x2) * (z1z2 + dt1t2) 67 | * t3 = (y1y2 - ax1x2) * (x1y2 + y1x2) 68 | * z3 = (z1z2 - dt1t2) * (z1z2 + dt1t2) 69 | */ 70 | function pointAddASM( 71 | uint256[4] _p1, 72 | uint256[4] _p2 73 | ) 74 | internal 75 | pure 76 | returns (uint256[4] p3) 77 | { 78 | if (_p1[0] == 0 && _p1[1] == 0 && _p1[2] == 0 && _p1[3] == 0) { 79 | return _p2; 80 | } 81 | 82 | if (_p2[0] == 0 && _p2[1] == 0 && _p2[2] == 0 && _p2[3] == 0) { 83 | return _p1; 84 | } 85 | 86 | assembly { 87 | let localQ := 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001 88 | let localA := 0x292FC 89 | let localD := 0x292F8 90 | 91 | // A <- x1 * x2 92 | let a := mulmod(mload(_p1), mload(_p2), localQ) 93 | // B <- y1 * y2 94 | let b := mulmod(mload(add(_p1, 0x20)), mload(add(_p2, 0x20)), localQ) 95 | // C <- d * t1 * t2 96 | let c := mulmod(mulmod(localD, mload(add(_p1, 0x40)), localQ), mload(add(_p2, 0x40)), localQ) 97 | // D <- z1 * z2 98 | let d := mulmod(mload(add(_p1, 0x60)), mload(add(_p2, 0x60)), localQ) 99 | // E <- (x1 + y1) * (x2 + y2) - A - B 100 | let e := mulmod(addmod(mload(_p1), mload(add(_p1, 0x20)), localQ), addmod(mload(_p2), mload(add(_p2, 0x20)), localQ), localQ) 101 | if lt(e, add(a, 1)) { 102 | e := add(e, localQ) 103 | } 104 | e := mod(sub(e, a), localQ) 105 | if lt(e, add(b, 1)) { 106 | e := add(e, localQ) 107 | } 108 | e := mod(sub(e, b), localQ) 109 | // F <- D - C 110 | let f := d 111 | if lt(f, add(c, 1)) { 112 | f := add(f, localQ) 113 | } 114 | f := mod(sub(f, c), localQ) 115 | // G <- D + C 116 | let g := addmod(d, c, localQ) 117 | // H <- B - a * A 118 | let aA := mulmod(localA, a, localQ) 119 | let h := b 120 | if lt(h, add(aA, 1)) { 121 | h := add(h, localQ) 122 | } 123 | h := mod(sub(h, aA), localQ) 124 | 125 | // x3 <- E * F 126 | mstore(p3, mulmod(e, f, localQ)) 127 | // y3 <- G * H 128 | mstore(add(p3, 0x20), mulmod(g, h, localQ)) 129 | // t3 <- E * H 130 | mstore(add(p3, 0x40), mulmod(e, h, localQ)) 131 | // z3 <- F * G 132 | mstore(add(p3, 0x60), mulmod(f, g, localQ)) 133 | } 134 | } 135 | 136 | /** 137 | * @dev Double a etec point on baby jubjub curve 138 | * Doubling can be performed with the same formula as addition 139 | */ 140 | function pointDouble(uint256[4] _p) internal pure returns (uint256[4] p2) { 141 | p2 = pointAdd(_p, _p); 142 | } 143 | 144 | /** 145 | * @dev Double a etec point on baby jubjub curve 146 | * Doubling can be performed with the same formula as addition 147 | */ 148 | function pointDoubleASM(uint256[4] _p) internal pure returns (uint256[4] p2) { 149 | p2 = pointAddASM(_p, _p); 150 | } 151 | 152 | /** 153 | * @dev Double a etec point using dedicated double algorithm 154 | */ 155 | function pointDoubleDedicated(uint256[4] _p) internal pure returns (uint256[4] p2) { 156 | uint256[8] memory intermediates; 157 | // A <- x1 * x1 158 | intermediates[0] = mulmod(_p[0], _p[0], Q); 159 | // B <- y1 * y1 160 | intermediates[1] = mulmod(_p[1], _p[1], Q); 161 | // C <- 2 * z1 * z1 162 | intermediates[2] = mulmod(mulmod(2, _p[3], Q), _p[3], Q); 163 | // D <- a * A 164 | intermediates[3] = mulmod(A, intermediates[0], Q); 165 | // E <- (x1 + y1)^2 - A - B 166 | uint256 x1_plus_y1 = addmod(_p[0], _p[1], Q); 167 | intermediates[4] = submod(submod(mulmod(x1_plus_y1, x1_plus_y1, Q), intermediates[0], Q), intermediates[1], Q); 168 | // G <- D + B 169 | intermediates[5] = addmod(intermediates[3], intermediates[1], Q); 170 | // F <- G - C 171 | intermediates[6] = submod(intermediates[5], intermediates[2], Q); 172 | // H <- D - B 173 | intermediates[7] = submod(intermediates[3], intermediates[1], Q); 174 | 175 | // x3 <- E * F 176 | p2[0] = mulmod(intermediates[4], intermediates[6], Q); 177 | // y3 <- G * H 178 | p2[1] = mulmod(intermediates[5], intermediates[7], Q); 179 | // t3 <- E * H 180 | p2[2] = mulmod(intermediates[4], intermediates[7], Q); 181 | // z3 <- F * G 182 | p2[3] = mulmod(intermediates[6], intermediates[5], Q); 183 | } 184 | 185 | /** 186 | * @dev Double a etec point using dedicated double algorithm 187 | */ 188 | function pointDoubleDedicatedASM( 189 | uint256 _x, 190 | uint256 _y, 191 | uint256 _t, 192 | uint256 _z 193 | ) 194 | internal 195 | pure 196 | returns (uint256 x, uint256 y, uint256 t, uint256 z) 197 | { 198 | assembly { 199 | let localQ := 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001 200 | let localA := 0x292FC 201 | 202 | // A <- x1 * x1 203 | let a := mulmod(_x, _x, localQ) 204 | // B <- y1 * y1 205 | let b := mulmod(_y, _y, localQ) 206 | // C <- 2 * z1 * z1 207 | let c := mulmod(mulmod(2, _z, localQ), _z, localQ) 208 | // D <- a * A 209 | let d := mulmod(localA, a, localQ) 210 | // E <- (x1 + y1)^2 - A - B 211 | let e := addmod(_x, _y, localQ) 212 | e := mulmod(e, e, localQ) 213 | if lt(e, add(a, 1)) { 214 | e := add(e, localQ) 215 | } 216 | e := mod(sub(e, a), localQ) 217 | if lt(e, add(b, 1)) { 218 | e := add(e, localQ) 219 | } 220 | e := mod(sub(e, b), localQ) 221 | // G <- D + B 222 | let g := addmod(d, b, localQ) 223 | // F <- G - C 224 | let f := g 225 | if lt(f, add(c, 1)) { 226 | f := add(f, localQ) 227 | } 228 | f := mod(sub(f, c), localQ) 229 | // H <- D - B 230 | let h := d 231 | if lt(h, add(b, 1)) { 232 | h := add(h, localQ) 233 | } 234 | h := mod(sub(h, b), localQ) 235 | 236 | // x3 <- E * F 237 | x := mulmod(e, f, localQ) 238 | // y3 <- G * H 239 | y := mulmod(g, h, localQ) 240 | // t3 <- E * H 241 | t := mulmod(e, h, localQ) 242 | // z3 <- F * G 243 | z := mulmod(f, g, localQ) 244 | } 245 | } 246 | 247 | /** 248 | * @dev Multiply a etec point on baby jubjub curve by a scalar 249 | * Use the double and add algorithm 250 | */ 251 | function pointMul(uint256[4] _p, uint256 _d) internal pure returns (uint256[4] p) { 252 | uint256 remaining = _d; 253 | 254 | uint256[4] memory pp = _p; 255 | uint256[4] memory ap = [uint256(0), uint256(0), uint256(0), uint256(0)]; 256 | 257 | while (remaining != 0) { 258 | if ((remaining & 1) != 0) { 259 | // Binary digit is 1 so add 260 | ap = pointAdd(ap, pp); 261 | } 262 | 263 | pp = pointDouble(pp); 264 | 265 | remaining = remaining / 2; 266 | } 267 | 268 | p = ap; 269 | } 270 | 271 | /** 272 | * @dev Perform modular subtraction 273 | */ 274 | function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) { 275 | uint256 aNN = _a; 276 | 277 | if (_a <= _b) { 278 | aNN += _mod; 279 | } 280 | 281 | return addmod(aNN - _b, 0, _mod); 282 | } 283 | 284 | /** 285 | * @dev Compute modular inverse of a number 286 | */ 287 | function inverse(uint256 _a) internal view returns (uint256) { 288 | // We can use Euler's theorem instead of the extended Euclidean algorithm 289 | // Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m) 290 | return expmod(_a, Q - 2, Q); 291 | } 292 | 293 | /** 294 | * @dev Helper function to call the bigModExp precompile 295 | */ 296 | function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) { 297 | assembly { 298 | let memPtr := mload(0x40) 299 | mstore(memPtr, 0x20) // Length of base _b 300 | mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e 301 | mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m 302 | mstore(add(memPtr, 0x60), _b) // Base _b 303 | mstore(add(memPtr, 0x80), _e) // Exponent _e 304 | mstore(add(memPtr, 0xa0), _m) // Modulus _m 305 | 306 | // The bigModExp precompile is at 0x05 307 | let success := staticcall(gas, 0x05, memPtr, 0xc0, memPtr, 0x20) 308 | switch success 309 | case 0 { 310 | revert(0x0, 0x0) 311 | } default { 312 | o := mload(memPtr) 313 | } 314 | } 315 | } 316 | 317 | /** 318 | * @dev Convert etec point to affine point 319 | */ 320 | function etec2point(uint256[4] _etec) internal view returns (uint256[2] p) { 321 | uint256 invZ = inverse(_etec[3]); 322 | p[0] = mulmod(_etec[0], invZ, Q); 323 | p[1] = mulmod(_etec[1], invZ, Q); 324 | } 325 | 326 | /** 327 | * @dev Convert affine point to etec point 328 | */ 329 | function point2etec(uint256[2] _p) internal pure returns (uint256[4] etec) { 330 | etec[0] = _p[0]; 331 | etec[1] = _p[1]; 332 | etec[2] = mulmod(_p[0], _p[1], Q); 333 | etec[3] = 1; 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /contracts/CurveBabyJubJubHelper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./CurveBabyJubJub.sol"; 4 | 5 | 6 | contract CurveBabyJubJubHelper { 7 | function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) public view returns (uint256 x3, uint256 y3) { 8 | (x3, y3) = CurveBabyJubJub.pointAdd(_x1, _y1, _x2, _y2); 9 | } 10 | 11 | function pointMul(uint256 _x1, uint256 _y1, uint256 _d) public view returns (uint256 x2, uint256 y2) { 12 | (x2, y2) = CurveBabyJubJub.pointMul(_x1, _y1, _d); 13 | } 14 | 15 | function pointDouble(uint256 _x1, uint256 _y1) public view returns (uint256 x2, uint256 y2) { 16 | (x2, y2) = CurveBabyJubJub.pointDouble(_x1, _y1); 17 | } 18 | } -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /test/CurveBabyJubJub.js: -------------------------------------------------------------------------------- 1 | const CurveBabyJubJubHelper = artifacts.require("CurveBabyJubJubHelper") 2 | 3 | contract("CurveBabyJubJubHelper", () => { 4 | let curve 5 | 6 | before(async () => { 7 | curve = await CurveBabyJubJubHelper.new() 8 | }) 9 | 10 | describe("pointAdd", () => { 11 | it("adds 2 points on the curve", async () => { 12 | let g = await curve.pointAdd.estimateGas(0, 0, 0, 0) 13 | console.log(g) 14 | 15 | let x1 = "0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5" 16 | let y1 = "0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1" 17 | g = await curve.pointAdd.estimateGas(x1, y1, x1, y1) 18 | console.log(g) 19 | 20 | let x2 = "0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C" 21 | let y2 = "0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853" 22 | g = await curve.pointAdd.estimateGas(x1, y1, x2, y2) 23 | console.log(g) 24 | }) 25 | }) 26 | 27 | describe("pointDouble", () => { 28 | it("doubles a point", async () => { 29 | let x1 = "0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C" 30 | let y1 = "0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853" 31 | 32 | let g = await curve.pointDouble.estimateGas(x1, y1) 33 | console.log(g) 34 | 35 | x1 = "0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5" 36 | y1 = "0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1" 37 | 38 | g = await curve.pointDouble.estimateGas(x1, y1) 39 | console.log(g) 40 | 41 | x1 = "0x5234237DB48A066A4E072C8A345DE7BB0F5A1D7230B6D62BDAA3E317E56A820" 42 | y1 = "0x2B970CF66A6744AACFF7C68DAB8DE8BF9F49AE8A56BF78F60E992F65708A36A3" 43 | 44 | g = await curve.pointDouble.estimateGas(x1, y1) 45 | console.log(g) 46 | }) 47 | }) 48 | 49 | describe("pointMul", () => { 50 | it("multiplies a point by a scalar", async () => { 51 | let x1 = "0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C" 52 | let y1 = "0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853" 53 | 54 | let g = await curve.pointMul.estimateGas(x1, y1, 1) 55 | console.log(g) 56 | 57 | g = await curve.pointMul.estimateGas(x1, y1, 2) 58 | console.log(g) 59 | 60 | g = await curve.pointMul.estimateGas(x1, y1, 7) 61 | console.log(g) 62 | }) 63 | }) 64 | }) -------------------------------------------------------------------------------- /test/TestCurveBabyJubJub.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "../contracts/CurveBabyJubJub.sol"; 4 | import "truffle/Assert.sol"; 5 | 6 | 7 | contract TestCurveBabyJubJub { 8 | function test_isOnCurve() public { 9 | uint256 x1 = 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C; 10 | uint256 y1 = 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853; 11 | Assert.isTrue(CurveBabyJubJub.isOnCurve(x1, y1), "point should be on curve"); 12 | 13 | uint256 x2 = 0x2491ABA8D3A191A76E35BC47BD9AFE6CC88FEE14D607CBE779F2349047D5C157; 14 | uint256 y2 = 0x2E07297F8D3C3D7818DBDDFD24C35583F9A9D4ED0CB0C1D1348DD8F7F99152D7; 15 | Assert.isTrue(CurveBabyJubJub.isOnCurve(x2, y2), "point should be on curve"); 16 | } 17 | 18 | function test_pointAdd() public { 19 | uint256 x1 = 0; 20 | uint256 y1 = 0; 21 | uint256 x2 = 0; 22 | uint256 y2 = 0; 23 | (uint256 x3, uint256 y3) = CurveBabyJubJub.pointAdd(x1, y1, x2, y2); 24 | Assert.equal(x3, 0, "should add (0, 0)"); 25 | Assert.equal(y3, 0, "should add (0, 0)"); 26 | 27 | x1 = 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C; 28 | y1 = 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853; 29 | (x3, y3) = CurveBabyJubJub.pointAdd(x1, y1, 0, 1); 30 | Assert.equal(x3, 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, "should add (0, 1)"); 31 | Assert.equal(y3, 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853, "should add (0, 1)"); 32 | Assert.isTrue(CurveBabyJubJub.isOnCurve(x3, y3), "point should be on curve"); 33 | 34 | (x3, y3) = CurveBabyJubJub.pointAdd(x1, y1, x1, y1); 35 | Assert.equal(x3, 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should add self"); 36 | Assert.equal(y3, 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should add self"); 37 | Assert.isTrue(CurveBabyJubJub.isOnCurve(x3, y3), "point should be on curve"); 38 | } 39 | 40 | function test_pointDouble() public { 41 | uint256 x1 = 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C; 42 | uint256 y1 = 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853; 43 | (uint256 x3, uint256 y3) = CurveBabyJubJub.pointDouble(x1, y1); 44 | Assert.equal(x3, 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should double"); 45 | Assert.equal(y3, 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should double"); 46 | Assert.isTrue(CurveBabyJubJub.isOnCurve(x3, y3), "point should be on curve"); 47 | } 48 | 49 | function test_pointMul() public { 50 | uint256 x1 = 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C; 51 | uint256 y1 = 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853; 52 | 53 | // 1 * (x1, y1) 54 | uint256 d = 1; 55 | (uint256 x2, uint256 y2) = CurveBabyJubJub.pointMul(x1, y1, d); 56 | Assert.equal(x2, 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, "should multiply by 1"); 57 | Assert.equal(y2, 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853, "should multiply by 1"); 58 | 59 | // 2 * (x1, y1) 60 | d = 2; 61 | (x2, y2) = CurveBabyJubJub.pointMul(x1, y1, d); 62 | Assert.equal(x2, 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should multiply by 2"); 63 | Assert.equal(y2, 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should multiply by 2"); 64 | 65 | // 7 * (x1, y1) 66 | d = 7; 67 | (x2, y2) = CurveBabyJubJub.pointMul(x1, y1, d); 68 | Assert.equal(x2, 0x5234237DB48A066A4E072C8A345DE7BB0F5A1D7230B6D62BDAA3E317E56A820, "should multiply by 7"); 69 | Assert.equal(y2, 0x2B970CF66A6744AACFF7C68DAB8DE8BF9F49AE8A56BF78F60E992F65708A36A3, "should multiply by 7"); 70 | 71 | // 15 * (x1, y1) 72 | d = 15; 73 | (x2, y2) = CurveBabyJubJub.pointMul(x1, y1, d); 74 | Assert.equal(x2, 0x14CC5477CD37C561309C318701C7B0A311FA5E8B7BCEB07849E5287037C20079, "should multiply by 15"); 75 | Assert.equal(y2, 0xEFC81E2338DF9EEE05230F48F33D1A29FE9786A589D5889310ADC492D2C7870, "should multiply by 15"); 76 | 77 | // 31 * (x1, y1) 78 | d = 31; 79 | (x2, y2) = CurveBabyJubJub.pointMul(x1, y1, d); 80 | Assert.equal(x2, 0x10DA60B985EF1F51DE59AA19A65E6EC7691ED298F51B5C5316862432EE1BFABC, "should multiply by 31"); 81 | Assert.equal(y2, 0x444B1F4CE7B3DE187297A85E6E8D84FD3FBE929EAF90D5E6F22DCA4F4163B9, "should multiply by 31"); 82 | } 83 | } -------------------------------------------------------------------------------- /test/TestCurveBabyJubJubExtended.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "../contracts/CurveBabyJubJubExtended.sol"; 4 | import "truffle/Assert.sol"; 5 | 6 | 7 | contract TestCurveBabyJubJubExtended { 8 | function test_pointAdd() public { 9 | uint256[2] memory p = [uint256(0), uint256(0)]; 10 | uint256[4] memory etec = CurveBabyJubJubExtended.point2etec(p); 11 | uint256[4] memory resEtec = CurveBabyJubJubExtended.pointAdd(etec, etec); 12 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 13 | Assert.equal(resPoint[0], 0, "should add (0, 0)"); 14 | Assert.equal(resPoint[1], 0, "should add (0, 0)"); 15 | 16 | p = [ 17 | 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, 18 | 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853 19 | ]; 20 | etec = CurveBabyJubJubExtended.point2etec(p); 21 | resEtec = CurveBabyJubJubExtended.pointAdd(etec, etec); 22 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 23 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should add self"); 24 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should add self"); 25 | } 26 | 27 | function test_pointAddASM() public { 28 | uint256[2] memory p = [uint256(0), uint256(0)]; 29 | uint256[4] memory etec = CurveBabyJubJubExtended.point2etec(p); 30 | uint256[4] memory resEtec = CurveBabyJubJubExtended.pointAddASM(etec, etec); 31 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 32 | Assert.equal(resPoint[0], 0, "should add (0, 0)"); 33 | Assert.equal(resPoint[1], 0, "should add (0, 0)"); 34 | 35 | p = [ 36 | 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, 37 | 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853 38 | ]; 39 | etec = CurveBabyJubJubExtended.point2etec(p); 40 | resEtec = CurveBabyJubJubExtended.pointAddASM(etec, etec); 41 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 42 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should add self"); 43 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should add self"); 44 | } 45 | 46 | function test_pointDouble() public { 47 | uint256[2] memory p = [ 48 | 0x274dbce8d15179969bc0d49fa725bddf9de555e0ba6a693c6adb52fc9ee7a82c, 49 | 0x5ce98c61b05f47fe2eae9a542bd99f6b2e78246231640b54595febfd51eb853 50 | ]; 51 | 52 | uint256[4] memory res = CurveBabyJubJubExtended.pointDouble(CurveBabyJubJubExtended.point2etec(p)); 53 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(res); 54 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should double"); 55 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should double"); 56 | } 57 | 58 | function test_pointDoubleASM() public { 59 | uint256[2] memory p = [ 60 | 0x274dbce8d15179969bc0d49fa725bddf9de555e0ba6a693c6adb52fc9ee7a82c, 61 | 0x5ce98c61b05f47fe2eae9a542bd99f6b2e78246231640b54595febfd51eb853 62 | ]; 63 | 64 | uint256[4] memory res = CurveBabyJubJubExtended.pointDoubleASM(CurveBabyJubJubExtended.point2etec(p)); 65 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(res); 66 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should double"); 67 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should double"); 68 | } 69 | 70 | function test_pointDoubleDedicated() public { 71 | uint256[2] memory p = [ 72 | 0x274dbce8d15179969bc0d49fa725bddf9de555e0ba6a693c6adb52fc9ee7a82c, 73 | 0x5ce98c61b05f47fe2eae9a542bd99f6b2e78246231640b54595febfd51eb853 74 | ]; 75 | 76 | uint256[4] memory res = CurveBabyJubJubExtended.pointDoubleDedicated(CurveBabyJubJubExtended.point2etec(p)); 77 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(res); 78 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should double"); 79 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should double"); 80 | } 81 | 82 | function test_pointDoubleDedicatedASM() public { 83 | uint256[2] memory p = [ 84 | 0x274dbce8d15179969bc0d49fa725bddf9de555e0ba6a693c6adb52fc9ee7a82c, 85 | 0x5ce98c61b05f47fe2eae9a542bd99f6b2e78246231640b54595febfd51eb853 86 | ]; 87 | uint256[4] memory etec = CurveBabyJubJubExtended.point2etec(p); 88 | 89 | (uint256 x, uint256 y, uint256 t, uint256 z) = CurveBabyJubJubExtended.pointDoubleDedicatedASM(etec[0], etec[1], etec[2], etec[3]); 90 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point([x, y, t, z]); 91 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should double"); 92 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should double"); 93 | } 94 | 95 | function test_pointMul() public { 96 | uint256[2] memory p = [ 97 | 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, 98 | 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853 99 | ]; 100 | uint256[4] memory etec = CurveBabyJubJubExtended.point2etec(p); 101 | 102 | // 1 * (x1, y1) 103 | uint256 d = 1; 104 | uint256[4] memory resEtec = CurveBabyJubJubExtended.pointMul(etec, d); 105 | uint256[2] memory resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 106 | Assert.equal(resPoint[0], 0x274DBCE8D15179969BC0D49FA725BDDF9DE555E0BA6A693C6ADB52FC9EE7A82C, "should multiply by 1"); 107 | Assert.equal(resPoint[1], 0x5CE98C61B05F47FE2EAE9A542BD99F6B2E78246231640B54595FEBFD51EB853, "should multiply by 1"); 108 | 109 | // 2 * (x1, y1) 110 | d = 2; 111 | resEtec = CurveBabyJubJubExtended.pointMul(etec, d); 112 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 113 | Assert.equal(resPoint[0], 0xF3C160E26FC96C347DD9E705EB5A3E8D661502728609FF95B3B889296901AB5, "should multiply by 2"); 114 | Assert.equal(resPoint[1], 0x9979273078B5C735585107619130E62E315C5CAFE683A064F79DFED17EB14E1, "should multiply by 2"); 115 | 116 | // 7 * (x1, y1) 117 | d = 7; 118 | resEtec = CurveBabyJubJubExtended.pointMul(etec, d); 119 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 120 | Assert.equal(resPoint[0], 0x5234237DB48A066A4E072C8A345DE7BB0F5A1D7230B6D62BDAA3E317E56A820, "should multiply by 7"); 121 | Assert.equal(resPoint[1], 0x2B970CF66A6744AACFF7C68DAB8DE8BF9F49AE8A56BF78F60E992F65708A36A3, "should multiply by 7"); 122 | 123 | // 15 * (x1, y1) 124 | d = 15; 125 | resEtec = CurveBabyJubJubExtended.pointMul(etec, d); 126 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 127 | Assert.equal(resPoint[0], 0x14CC5477CD37C561309C318701C7B0A311FA5E8B7BCEB07849E5287037C20079, "should multiply by 15"); 128 | Assert.equal(resPoint[1], 0xEFC81E2338DF9EEE05230F48F33D1A29FE9786A589D5889310ADC492D2C7870, "should multiply by 15"); 129 | 130 | // 31 * (x1, y1) 131 | d = 31; 132 | resEtec = CurveBabyJubJubExtended.pointMul(etec, d); 133 | resPoint = CurveBabyJubJubExtended.etec2point(resEtec); 134 | Assert.equal(resPoint[0], 0x10DA60B985EF1F51DE59AA19A65E6EC7691ED298F51B5C5316862432EE1BFABC, "should multiply by 31"); 135 | Assert.equal(resPoint[1], 0x444B1F4CE7B3DE187297A85E6E8D84FD3FBE929EAF90D5E6F22DCA4F4163B9, "should multiply by 31"); 136 | 137 | } 138 | } -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura API 13 | * keys are available for free at: infura.io/register 14 | * 15 | * > > Using Truffle V5 or later? Make sure you install the `web3-one` version. 16 | * 17 | * > > $ npm install truffle-hdwallet-provider@web3-one 18 | * 19 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 20 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 21 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 22 | * 23 | */ 24 | 25 | // const HDWallet = require('truffle-hdwallet-provider'); 26 | // const infuraKey = "fj4jll3k....."; 27 | // 28 | // const fs = require('fs'); 29 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 30 | 31 | module.exports = { 32 | /** 33 | * Networks define how you connect to your ethereum client and let you set the 34 | * defaults web3 uses to send transactions. If you don't specify one truffle 35 | * will spin up a development blockchain for you on port 9545 when you 36 | * run `develop` or `test`. You can ask a truffle command to use a specific 37 | * network from the command line, e.g 38 | * 39 | * $ truffle test --network 40 | */ 41 | 42 | networks: { 43 | // Useful for testing. The `development` name is special - truffle uses it by default 44 | // if it's defined here and no other network is specified at the command line. 45 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 46 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 47 | // options below to some value. 48 | // 49 | // development: { 50 | // host: "127.0.0.1", // Localhost (default: none) 51 | // port: 8545, // Standard Ethereum port (default: none) 52 | // network_id: "*", // Any network (default: none) 53 | // }, 54 | 55 | // Another network with more advanced options... 56 | advanced: { 57 | // port: 8777, // Custom port 58 | // network_id: 1342, // Custom network 59 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 60 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 61 | // from:
, // Account to send txs from (default: accounts[0]) 62 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 63 | }, 64 | 65 | // Useful for deploying to a public network. 66 | // NB: It's important to wrap the provider as a function. 67 | ropsten: { 68 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/${infuraKey}`), 69 | // network_id: 3, // Ropsten's id 70 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 71 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 72 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 73 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 74 | }, 75 | 76 | // Useful for private networks 77 | private: { 78 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 79 | // network_id: 2111, // This network is yours, in the cloud. 80 | // production: true // Treats this network as if it was a public net. (default: false) 81 | } 82 | }, 83 | 84 | // Set default mocha options here, use special reporters etc. 85 | mocha: { 86 | // timeout: 100000 87 | }, 88 | 89 | // Configure your compilers 90 | compilers: { 91 | solc: { 92 | // version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version) 93 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 94 | // settings: { // See the solidity docs for advice about optimization and evmVersion 95 | // optimizer: { 96 | // enabled: false, 97 | // runs: 200 98 | // }, 99 | // evmVersion: "byzantium" 100 | // } 101 | } 102 | } 103 | } 104 | --------------------------------------------------------------------------------