├── LICENSE ├── README.md ├── contracts ├── Migrations.sol ├── curves │ └── EllipticCurve.sol └── ownership │ └── Ownable.sol ├── migrations └── 1_initial_migration.js ├── package.json ├── test ├── curves │ └── EllipticCurve.test.js └── helpers │ └── assertRevert.js └── truffle.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tilman Drerup 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elliptic-curve-solidity 2 | 3 | A pure Solidity implementation of elliptic curve secp256r1 / prime256v1 / p256. 4 | 5 | #### Signature verification 6 | 7 | The main purpose of this contract is verification of ECDSA signatures based on curve secp256r1 / prime256v1 / p256. To verify a signature, use the function 8 | 9 | function validateSignature(bytes32 message, uint[2] memory rs, uint[2] memory Q) public pure 10 | returns (bool) 11 | 12 | where 13 | 14 | * `bytes32 message` is the hash of the signed message 15 | * `uint[2] rs` contains the signature 16 | * `uint[2] Q` contains the coordinates of the public key 17 | 18 | The function returns `true` for valid signatures, `false` otherwise. 19 | 20 | Notes: 21 | 22 | * To disambiguate public keys when verifying signatures, activate condition `rs[1] > lowSmax` in `validateSignature()`. 23 | * To run the tests, first install the node packages (`npm install`) and then run `truffle test`. 24 | * Verifying signatures is costly (!) in terms of gas. 25 | 26 | #### Miscellanea 27 | 28 | * Tested with Solidity 0.5.0 and Truffle v5.0.1. 29 | * Some newer versions of web3.js cause issues due to improper handling of bigNumber objects. 30 | * Some components of the contract are based on code written by Andreas Olofsson, Alexander Vlasov (https://github.com/BANKEX/CurveArithmetics), and Avi Asayag (https://github.com/orbs-network/elliptic-curve-solidity). 31 | * Versions of the contract have been deployed on the main Ethereum network (https://etherscan.io/address/0xf471789937856d80e589f5996cf8b0511ddd9de4) as well as the Ropsten test network (https://ropsten.etherscan.io/address/0x8025532f39e089d8bb3ed783ccdd974ee8c3948f). 32 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import './ownership/Ownable.sol'; 4 | 5 | /** 6 | * @dev Truffle migrations manager. 7 | */ 8 | contract Migrations is 9 | Ownable 10 | { 11 | uint public lastCompletedMigration; 12 | 13 | /** 14 | * @dev Contract constructor. 15 | */ 16 | constructor() 17 | public 18 | { 19 | owner = msg.sender; 20 | } 21 | 22 | /** 23 | * @dev Sets migration state. 24 | * @param _completed Last completed migration number. 25 | */ 26 | function setCompleted( 27 | uint _completed 28 | ) 29 | public 30 | onlyOwner() 31 | { 32 | lastCompletedMigration = _completed; 33 | } 34 | 35 | /** 36 | * @dev Permorms migration. 37 | * @param _addr New migration address. 38 | */ 39 | function upgrade( 40 | address _addr 41 | ) 42 | public 43 | onlyOwner() 44 | { 45 | Migrations upgraded = Migrations(_addr); 46 | upgraded.setCompleted(lastCompletedMigration); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /contracts/curves/EllipticCurve.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title EllipticCurve 5 | * 6 | * @author Tilman Drerup; 7 | * 8 | * @notice Implements elliptic curve math; Parametrized for SECP256R1. 9 | * 10 | * Includes components of code by Andreas Olofsson, Alexander Vlasov 11 | * (https://github.com/BANKEX/CurveArithmetics), and Avi Asayag 12 | * (https://github.com/orbs-network/elliptic-curve-solidity) 13 | * 14 | * @dev NOTE: To disambiguate public keys when verifying signatures, activate 15 | * condition 'rs[1] > lowSmax' in validateSignature(). 16 | */ 17 | contract EllipticCurve { 18 | 19 | // Set parameters for curve. 20 | uint constant a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC; 21 | uint constant b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B; 22 | uint constant gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296; 23 | uint constant gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5; 24 | uint constant p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; 25 | uint constant n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; 26 | 27 | uint constant lowSmax = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; 28 | 29 | /** 30 | * @dev Inverse of u in the field of modulo m. 31 | */ 32 | function inverseMod(uint u, uint m) internal pure 33 | returns (uint) 34 | { 35 | if (u == 0 || u == m || m == 0) 36 | return 0; 37 | if (u > m) 38 | u = u % m; 39 | 40 | int t1; 41 | int t2 = 1; 42 | uint r1 = m; 43 | uint r2 = u; 44 | uint q; 45 | 46 | while (r2 != 0) { 47 | q = r1 / r2; 48 | (t1, t2, r1, r2) = (t2, t1 - int(q) * t2, r2, r1 - q * r2); 49 | } 50 | 51 | if (t1 < 0) 52 | return (m - uint(-t1)); 53 | 54 | return uint(t1); 55 | } 56 | 57 | /** 58 | * @dev Transform affine coordinates into projective coordinates. 59 | */ 60 | function toProjectivePoint(uint x0, uint y0) public pure 61 | returns (uint[3] memory P) 62 | { 63 | P[2] = addmod(0, 1, p); 64 | P[0] = mulmod(x0, P[2], p); 65 | P[1] = mulmod(y0, P[2], p); 66 | } 67 | 68 | /** 69 | * @dev Add two points in affine coordinates and return projective point. 70 | */ 71 | function addAndReturnProjectivePoint(uint x1, uint y1, uint x2, uint y2) public pure 72 | returns (uint[3] memory P) 73 | { 74 | uint x; 75 | uint y; 76 | (x, y) = add(x1, y1, x2, y2); 77 | P = toProjectivePoint(x, y); 78 | } 79 | 80 | /** 81 | * @dev Transform from projective to affine coordinates. 82 | */ 83 | function toAffinePoint(uint x0, uint y0, uint z0) public pure 84 | returns (uint x1, uint y1) 85 | { 86 | uint z0Inv; 87 | z0Inv = inverseMod(z0, p); 88 | x1 = mulmod(x0, z0Inv, p); 89 | y1 = mulmod(y0, z0Inv, p); 90 | } 91 | 92 | /** 93 | * @dev Return the zero curve in projective coordinates. 94 | */ 95 | function zeroProj() public pure 96 | returns (uint x, uint y, uint z) 97 | { 98 | return (0, 1, 0); 99 | } 100 | 101 | /** 102 | * @dev Return the zero curve in affine coordinates. 103 | */ 104 | function zeroAffine() public pure 105 | returns (uint x, uint y) 106 | { 107 | return (0, 0); 108 | } 109 | 110 | /** 111 | * @dev Check if the curve is the zero curve. 112 | */ 113 | function isZeroCurve(uint x0, uint y0) public pure 114 | returns (bool isZero) 115 | { 116 | if(x0 == 0 && y0 == 0) { 117 | return true; 118 | } 119 | return false; 120 | } 121 | 122 | /** 123 | * @dev Check if a point in affine coordinates is on the curve. 124 | */ 125 | function isOnCurve(uint x, uint y) public pure 126 | returns (bool) 127 | { 128 | if (0 == x || x == p || 0 == y || y == p) { 129 | return false; 130 | } 131 | 132 | uint LHS = mulmod(y, y, p); // y^2 133 | uint RHS = mulmod(mulmod(x, x, p), x, p); // x^3 134 | 135 | if (a != 0) { 136 | RHS = addmod(RHS, mulmod(x, a, p), p); // x^3 + a*x 137 | } 138 | if (b != 0) { 139 | RHS = addmod(RHS, b, p); // x^3 + a*x + b 140 | } 141 | 142 | return LHS == RHS; 143 | } 144 | 145 | /** 146 | * @dev Double an elliptic curve point in projective coordinates. See 147 | * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates 148 | */ 149 | function twiceProj(uint x0, uint y0, uint z0) public pure 150 | returns (uint x1, uint y1, uint z1) 151 | { 152 | uint t; 153 | uint u; 154 | uint v; 155 | uint w; 156 | 157 | if(isZeroCurve(x0, y0)) { 158 | return zeroProj(); 159 | } 160 | 161 | u = mulmod(y0, z0, p); 162 | u = mulmod(u, 2, p); 163 | 164 | v = mulmod(u, x0, p); 165 | v = mulmod(v, y0, p); 166 | v = mulmod(v, 2, p); 167 | 168 | x0 = mulmod(x0, x0, p); 169 | t = mulmod(x0, 3, p); 170 | 171 | z0 = mulmod(z0, z0, p); 172 | z0 = mulmod(z0, a, p); 173 | t = addmod(t, z0, p); 174 | 175 | w = mulmod(t, t, p); 176 | x0 = mulmod(2, v, p); 177 | w = addmod(w, p-x0, p); 178 | 179 | x0 = addmod(v, p-w, p); 180 | x0 = mulmod(t, x0, p); 181 | y0 = mulmod(y0, u, p); 182 | y0 = mulmod(y0, y0, p); 183 | y0 = mulmod(2, y0, p); 184 | y1 = addmod(x0, p-y0, p); 185 | 186 | x1 = mulmod(u, w, p); 187 | 188 | z1 = mulmod(u, u, p); 189 | z1 = mulmod(z1, u, p); 190 | } 191 | 192 | /** 193 | * @dev Add two elliptic curve points in projective coordinates. See 194 | * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates 195 | */ 196 | function addProj(uint x0, uint y0, uint z0, uint x1, uint y1, uint z1) public pure 197 | returns (uint x2, uint y2, uint z2) 198 | { 199 | uint t0; 200 | uint t1; 201 | uint u0; 202 | uint u1; 203 | 204 | if (isZeroCurve(x0, y0)) { 205 | return (x1, y1, z1); 206 | } 207 | else if (isZeroCurve(x1, y1)) { 208 | return (x0, y0, z0); 209 | } 210 | 211 | t0 = mulmod(y0, z1, p); 212 | t1 = mulmod(y1, z0, p); 213 | 214 | u0 = mulmod(x0, z1, p); 215 | u1 = mulmod(x1, z0, p); 216 | 217 | if (u0 == u1) { 218 | if (t0 == t1) { 219 | return twiceProj(x0, y0, z0); 220 | } 221 | else { 222 | return zeroProj(); 223 | } 224 | } 225 | 226 | (x2, y2, z2) = addProj2(mulmod(z0, z1, p), u0, u1, t1, t0); 227 | } 228 | 229 | /** 230 | * @dev Helper function that splits addProj to avoid too many local variables. 231 | */ 232 | function addProj2(uint v, uint u0, uint u1, uint t1, uint t0) private pure 233 | returns (uint x2, uint y2, uint z2) 234 | { 235 | uint u; 236 | uint u2; 237 | uint u3; 238 | uint w; 239 | uint t; 240 | 241 | t = addmod(t0, p-t1, p); 242 | u = addmod(u0, p-u1, p); 243 | u2 = mulmod(u, u, p); 244 | 245 | w = mulmod(t, t, p); 246 | w = mulmod(w, v, p); 247 | u1 = addmod(u1, u0, p); 248 | u1 = mulmod(u1, u2, p); 249 | w = addmod(w, p-u1, p); 250 | 251 | x2 = mulmod(u, w, p); 252 | 253 | u3 = mulmod(u2, u, p); 254 | u0 = mulmod(u0, u2, p); 255 | u0 = addmod(u0, p-w, p); 256 | t = mulmod(t, u0, p); 257 | t0 = mulmod(t0, u3, p); 258 | 259 | y2 = addmod(t, p-t0, p); 260 | 261 | z2 = mulmod(u3, v, p); 262 | } 263 | 264 | /** 265 | * @dev Add two elliptic curve points in affine coordinates. 266 | */ 267 | function add(uint x0, uint y0, uint x1, uint y1) public pure 268 | returns (uint, uint) 269 | { 270 | uint z0; 271 | 272 | (x0, y0, z0) = addProj(x0, y0, 1, x1, y1, 1); 273 | 274 | return toAffinePoint(x0, y0, z0); 275 | } 276 | 277 | /** 278 | * @dev Double an elliptic curve point in affine coordinates. 279 | */ 280 | function twice(uint x0, uint y0) public pure 281 | returns (uint, uint) 282 | { 283 | uint z0; 284 | 285 | (x0, y0, z0) = twiceProj(x0, y0, 1); 286 | 287 | return toAffinePoint(x0, y0, z0); 288 | } 289 | 290 | /** 291 | * @dev Multiply an elliptic curve point by a 2 power base (i.e., (2^exp)*P)). 292 | */ 293 | function multiplyPowerBase2(uint x0, uint y0, uint exp) public pure 294 | returns (uint, uint) 295 | { 296 | uint base2X = x0; 297 | uint base2Y = y0; 298 | uint base2Z = 1; 299 | 300 | for(uint i = 0; i < exp; i++) { 301 | (base2X, base2Y, base2Z) = twiceProj(base2X, base2Y, base2Z); 302 | } 303 | 304 | return toAffinePoint(base2X, base2Y, base2Z); 305 | } 306 | 307 | /** 308 | * @dev Multiply an elliptic curve point by a scalar. 309 | */ 310 | function multiplyScalar(uint x0, uint y0, uint scalar) public pure 311 | returns (uint x1, uint y1) 312 | { 313 | if(scalar == 0) { 314 | return zeroAffine(); 315 | } 316 | else if (scalar == 1) { 317 | return (x0, y0); 318 | } 319 | else if (scalar == 2) { 320 | return twice(x0, y0); 321 | } 322 | 323 | uint base2X = x0; 324 | uint base2Y = y0; 325 | uint base2Z = 1; 326 | uint z1 = 1; 327 | x1 = x0; 328 | y1 = y0; 329 | 330 | if(scalar%2 == 0) { 331 | x1 = y1 = 0; 332 | } 333 | 334 | scalar = scalar >> 1; 335 | 336 | while(scalar > 0) { 337 | (base2X, base2Y, base2Z) = twiceProj(base2X, base2Y, base2Z); 338 | 339 | if(scalar%2 == 1) { 340 | (x1, y1, z1) = addProj(base2X, base2Y, base2Z, x1, y1, z1); 341 | } 342 | 343 | scalar = scalar >> 1; 344 | } 345 | 346 | return toAffinePoint(x1, y1, z1); 347 | } 348 | 349 | /** 350 | * @dev Multiply the curve's generator point by a scalar. 351 | */ 352 | function multipleGeneratorByScalar(uint scalar) public pure 353 | returns (uint, uint) 354 | { 355 | return multiplyScalar(gx, gy, scalar); 356 | } 357 | 358 | /** 359 | * @dev Validate combination of message, signature, and public key. 360 | */ 361 | function validateSignature(bytes32 message, uint[2] memory rs, uint[2] memory Q) public pure 362 | returns (bool) 363 | { 364 | 365 | // To disambiguate between public key solutions, include comment below. 366 | if(rs[0] == 0 || rs[0] >= n || rs[1] == 0) {// || rs[1] > lowSmax) 367 | return false; 368 | } 369 | if (!isOnCurve(Q[0], Q[1])) { 370 | return false; 371 | } 372 | 373 | uint x1; 374 | uint x2; 375 | uint y1; 376 | uint y2; 377 | 378 | uint sInv = inverseMod(rs[1], n); 379 | (x1, y1) = multiplyScalar(gx, gy, mulmod(uint(message), sInv, n)); 380 | (x2, y2) = multiplyScalar(Q[0], Q[1], mulmod(rs[0], sInv, n)); 381 | uint[3] memory P = addAndReturnProjectivePoint(x1, y1, x2, y2); 382 | 383 | if (P[2] == 0) { 384 | return false; 385 | } 386 | 387 | uint Px = inverseMod(P[2], p); 388 | Px = mulmod(P[0], mulmod(Px, Px, p), p); 389 | 390 | return Px % n == rs[0]; 391 | } 392 | } -------------------------------------------------------------------------------- /contracts/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev The contract has an owner address, and provides basic authorization control whitch 5 | * simplifies the implementation of user permissions. This contract is based on the source code 6 | * at https://goo.gl/n2ZGVt. 7 | */ 8 | contract Ownable { 9 | address public owner; 10 | 11 | /** 12 | * @dev An event which is triggered when the owner is changed. 13 | * @param previousOwner The address of the previous owner. 14 | * @param newOwner The address of the new owner. 15 | */ 16 | event OwnershipTransferred( 17 | address indexed previousOwner, 18 | address indexed newOwner 19 | ); 20 | 21 | /** 22 | * @dev The constructor sets the original `owner` of the contract to the sender account. 23 | */ 24 | constructor() 25 | public 26 | { 27 | owner = msg.sender; 28 | } 29 | 30 | /** 31 | * @dev Throws if called by any account other than the owner. 32 | */ 33 | modifier onlyOwner() { 34 | require(msg.sender == owner); 35 | _; 36 | } 37 | 38 | /** 39 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 40 | * @param _newOwner The address to transfer ownership to. 41 | */ 42 | function transferOwnership( 43 | address _newOwner 44 | ) 45 | onlyOwner 46 | public 47 | { 48 | require(_newOwner != address(0)); 49 | emit OwnershipTransferred(owner, _newOwner); 50 | owner = _newOwner; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require('./Migrations.sol'); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elliptic-solidity", 3 | "version": "1.0.0", 4 | "description": "Elliptic curve implementation in solidity; includes secp256r1", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/tdrerup/elliptic-curve-solidity.git" 8 | }, 9 | "main": "truffle.js", 10 | "directories": { 11 | "contracts": "contracts", 12 | "migrations": "migrations", 13 | "test": "test" 14 | }, 15 | "scripts": { 16 | "clean": "rm -Rf ./build", 17 | "compile": "truffle compile", 18 | "console": "truffle console", 19 | "flatten": "mkdir -p build && truffle-flattener contracts/**/*.sol >> build/bundle.sol", 20 | "lint": "eslint './**/*.js?(x)'", 21 | "migrate": "truffle migrate", 22 | "networks": "truffle networks", 23 | "postpublish": "npm run clean", 24 | "prepublish": "npm run compile", 25 | "test": "npm run clean && truffle test" 26 | }, 27 | "author": "tilman drerup", 28 | "license": "MIT", 29 | "keywords": [ 30 | "blockchain", 31 | "contract", 32 | "contracts", 33 | "ecc", 34 | "elliptic", 35 | "eth", 36 | "ethereum", 37 | "secp256r1", 38 | "smart", 39 | "smart-contract", 40 | "p256", 41 | "prime256v1" 42 | ], 43 | "devDependencies": { 44 | "bignumber.js": "^8.1.1", 45 | "crypto": "^1.0.1", 46 | "ec-pem": "^0.18.0", 47 | "ethers": "^4.0.27", 48 | "eslint": "^5.15.1", 49 | "ethereumjs-util": "^6.1.0", 50 | "ethjs-util": "^0.1.6", 51 | "truffle": "^5.0.7", 52 | "truffle-flattener": "^1.3.0", 53 | "web3": "1.0.0-beta.34", 54 | "web3-utils": "1.0.0-beta.34" 55 | }, 56 | "dependencies": { 57 | "solc": "^0.5.5" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/curves/EllipticCurve.test.js: -------------------------------------------------------------------------------- 1 | // Tilman Drerup (2018). 2 | 3 | // Test for EllipticCurve contract in SECP256R1 parametrization. 4 | const SECP256R1 = artifacts.require("./EllipticCurve.sol"); 5 | const assertRevert = require('../helpers/assertRevert'); 6 | const bigNumber = require('bignumber.js'); 7 | const crypto = require('crypto'); 8 | const ecPem = require('ec-pem'); 9 | const ethereumJSUtil = require('ethereumjs-util'); 10 | 11 | 12 | contract('SECP256R1', async (accounts) => { 13 | 14 | let curve; 15 | let messageHash; 16 | let publicKey; 17 | let signature; 18 | 19 | beforeEach(async () => { 20 | 21 | // Create contract. 22 | curve = await SECP256R1.new(); 23 | 24 | // Create curve object for key and signature generation. 25 | var prime256v1 = crypto.createECDH('prime256v1'); 26 | prime256v1.generateKeys(); 27 | 28 | // Reformat keys. 29 | var pemFormattedKeyPair = ecPem(prime256v1, 'prime256v1'); 30 | publicKey = [ 31 | '0x' + prime256v1.getPublicKey('hex').slice(2, 66), 32 | '0x' + prime256v1.getPublicKey('hex').slice(-64) 33 | ]; 34 | 35 | // Create random message and sha256-hash it. 36 | var message = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); 37 | messageHash = ethereumJSUtil.bufferToHex(ethereumJSUtil.sha256(message)); 38 | 39 | // Create signature. 40 | var signer = crypto.createSign('RSA-SHA256'); 41 | signer.update(message); 42 | var sigString = signer.sign(pemFormattedKeyPair.encodePrivateKey(), 'hex'); 43 | 44 | // Reformat signature / extract coordinates. 45 | var xlength = 2 * ('0x' + sigString.slice(6, 8)); 46 | var sigString = sigString.slice(8) 47 | signature = [ 48 | '0x' + sigString.slice(0, xlength), 49 | '0x' + sigString.slice(xlength + 4) 50 | ]; 51 | 52 | }); 53 | 54 | it('confirm that a valid point is on the curve', async() => { 55 | 56 | let x = "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" 57 | let y = "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5" 58 | 59 | var onCurve = await curve.isOnCurve(x, y); 60 | assert.equal(onCurve, true); 61 | 62 | }); 63 | 64 | it('reject that an invalid point is on the curve', async() => { 65 | 66 | let x = "0x3B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" 67 | let y = "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5" 68 | 69 | var onCurve = await curve.isOnCurve(x, y); 70 | assert.equal(onCurve, false); 71 | 72 | }); 73 | 74 | it('confirm valid signature (#1)', async () => { 75 | 76 | var result = await curve.validateSignature.call(messageHash, signature, publicKey); 77 | assert.equal(result, true); 78 | 79 | }); 80 | 81 | it('confirm valid signature (#2)', async () => { 82 | 83 | var result = await curve.validateSignature.call(messageHash, signature, publicKey); 84 | assert.equal(result, true); 85 | 86 | }); 87 | 88 | it('reject signature with flipped public key coordinates ([x,y] >> [y,x])', async () => { 89 | 90 | var flippedPublicKey = [publicKey[1], publicKey[0]]; 91 | var result = await curve.validateSignature.call(messageHash, signature, flippedPublicKey); 92 | assert.equal(result, false); 93 | 94 | }); 95 | 96 | it('reject signature with flipped signature values ([r,s] >> [s,r])', async () => { 97 | 98 | var flippedSignature = [signature[1], signature[0]]; 99 | var result = await curve.validateSignature.call(messageHash, flippedSignature, publicKey); 100 | assert.equal(result, false); 101 | 102 | }); 103 | 104 | it('reject signature with invalid message hash', async () => { 105 | 106 | var invalidMessage = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); 107 | var invalidMessageHash = ethereumJSUtil.bufferToHex(ethereumJSUtil.sha256(invalidMessage)); 108 | 109 | var result = await curve.validateSignature.call(invalidMessageHash, signature, publicKey); 110 | assert.equal(result, false); 111 | 112 | }); 113 | 114 | }); 115 | -------------------------------------------------------------------------------- /test/helpers/assertRevert.js: -------------------------------------------------------------------------------- 1 | // By openZeppelin 2 | module.exports = async (promise) => { 3 | try { 4 | await promise; 5 | assert.fail('Expected revert not received'); 6 | } catch (error) { 7 | const revertFound = error.message.search('revert') >= 0; 8 | assert(revertFound, `Expected "revert", got ${error} instead`); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | 'private': { 4 | host: 'localhost', 5 | port: 7545, 6 | network_id: '5777', 7 | from: '0xE862B6DA08aA5f146b1EE32C3D5dAB4e20BBFfB8', 8 | gas: 4000000, 9 | }, 10 | }, 11 | compilers: { 12 | solc: { 13 | version: "0.5.1" 14 | /* ... */ 15 | } 16 | 17 | /* ... */ 18 | }, 19 | }; --------------------------------------------------------------------------------