├── .prettierrc.json ├── scripts ├── build_ecdsa_verify │ ├── build_ecdsa_verify.circom │ ├── build_ecdsa_verify.sh │ └── ecdsa_verify.js ├── build_ecdsa_verify_no_precompute │ ├── build_ecdsa_verify_no_precompute.circom │ ├── build_ecdsa_verify_no_precompute.sh │ └── ecdsa_verify_no_precompute.js ├── build_ecdsa_verify_pubkey_to_addr │ ├── build_ecdsa_verify_pubkey_to_addr.circom │ ├── build_ecdsa_verify_pubkey_to_addr.sh │ └── ecdsa_verify_pubkey_to_addr.js └── utils │ ├── config.js │ ├── utils.js │ └── point-cache.js ├── .vscode └── settings.json ├── .gitignore ├── bench ├── index.html └── prover.js ├── .eslintrc.js ├── package.json ├── circuits ├── ecdsa_verify_no_precompute.circom ├── ecdsa_verify.circom ├── ecdsa_verify_pubkey_to_addr.circom ├── circom-ecdsa-circuits │ ├── vocdoni-keccak │ │ ├── utils.circom │ │ ├── keccak.circom │ │ └── permutations.circom │ ├── bigint_4x64_mult.circom │ ├── zk-identity │ │ └── eth.circom │ ├── secp256k1_func.circom │ ├── secp256k1_utils.circom │ ├── ecdsa.circom │ ├── bigint_func.circom │ ├── secp256k1.circom │ └── bigint.circom └── secp256k1_scalar_mult_cached_windowed.circom ├── README.md └── LICENSE /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": false, 6 | "arrowParens": "avoid", 7 | "uppercase": true 8 | } -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify/build_ecdsa_verify.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "../../circuits/ecdsa_verify.circom"; 3 | component main { public [TPreComputes, U] } = ECDSAVerify(64, 4); -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": ["groth", "SECP", "snarkjs", "ecsign", "zkey"], 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /*_js/ 3 | /node_modules 4 | keys/ 5 | build/ 6 | 7 | *.ptau 8 | *.r1cs 9 | *.zkey 10 | *.wasm 11 | 12 | yarn-error.log 13 | input.json 14 | setup-phase2.sh 15 | 16 | .DS_Store -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify_no_precompute/build_ecdsa_verify_no_precompute.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "../../circuits/ecdsa_verify_no_precompute.circom"; 3 | component main { public [T, U] } = ECDSAVerifyNoPrecompute(64, 4); -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify_pubkey_to_addr/build_ecdsa_verify_pubkey_to_addr.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "../../circuits/ecdsa_verify_pubkey_to_addr.circom"; 3 | component main { public [TPreComputes, U] } = ECDSAVerifyPubKeyToAddr(64, 4); -------------------------------------------------------------------------------- /scripts/utils/config.js: -------------------------------------------------------------------------------- 1 | const BN = require("bn.js"); 2 | 3 | const STRIDE = 8n; 4 | const NUM_STRIDES = 256n / STRIDE; // = 32 5 | const REGISTERS = 4n; 6 | 7 | const SECP256K1_N = new BN( 8 | "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 9 | 16 10 | ); 11 | 12 | module.exports = { 13 | STRIDE, 14 | NUM_STRIDES, 15 | REGISTERS, 16 | SECP256K1_N 17 | }; 18 | -------------------------------------------------------------------------------- /bench/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Benchmarking 6 | 7 | 8 |
9 | 10 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /bench/prover.js: -------------------------------------------------------------------------------- 1 | const prove = async (wasmFile, zKeyFile) => { 2 | console.log("Proving..."); 3 | console.time("fullProve"); 4 | 5 | const fullProof = await snarkjs.groth16.fullProve( 6 | sampleInput, 7 | wasmFile, 8 | zKeyFile 9 | ); 10 | 11 | console.log({ fullProof }); 12 | console.timeEnd("fullProve"); 13 | }; 14 | 15 | const verify = async () => { 16 | await prove( 17 | "https://d2q52de7b4rwg.cloudfront.net/ecdsa_verify.wasm", 18 | "https://d2q52de7b4rwg.cloudfront.net/ecdsa_verify.zkey" 19 | ); 20 | }; 21 | 22 | const verifyPubKeyToAddr = async () => { 23 | await prove( 24 | "https://d2q52de7b4rwg.cloudfront.net/ecdsa_verify_pubkey_to_addr.wasm", 25 | "https://d2q52de7b4rwg.cloudfront.net/ecdsa_verify_pubkey_to_addr.zkey" 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /scripts/utils/utils.js: -------------------------------------------------------------------------------- 1 | const { REGISTERS } = require("./config"); 2 | 3 | const addHexPrefix = str => `0x${str}`; 4 | 5 | const splitToRegisters = value => { 6 | const registers = []; 7 | 8 | if (!value) { 9 | return [0n, 0n, 0n, 0n]; 10 | } 11 | 12 | const hex = value.toString(16).padStart(64, "0"); 13 | for (let k = 0; k < REGISTERS; k++) { 14 | // 64bit = 16 chars in hex 15 | const val = hex.slice(k * 16, (k + 1) * 16); 16 | 17 | registers.unshift(BigInt(addHexPrefix(val))); 18 | } 19 | 20 | return registers.map(el => el.toString()); 21 | }; 22 | 23 | const registersToHex = registers => { 24 | return registers 25 | .map(el => BigInt(el).toString(16).padStart(16, "0")) 26 | .join(""); 27 | }; 28 | 29 | module.exports = { 30 | registersToHex, 31 | splitToRegisters 32 | }; 33 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:react/recommended", 7 | "plugin:react-hooks/recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:security/recommended" 10 | ], 11 | parser: "@typescript-eslint/parser", 12 | parserOptions: { 13 | ecmaFeatures: { 14 | jsx: true 15 | }, 16 | ecmaVersion: 13, 17 | sourceType: "module" 18 | }, 19 | plugins: ["react", "@typescript-eslint", "security"], 20 | rules: { 21 | "@typescript-eslint/no-var-requires": "off", 22 | "@typescript-eslint/ban-ts-comment": "off", 23 | "@typescript-eslint/no-explicit-any": "off", 24 | "react/react-in-jsx-scope": "off", 25 | "react/prop-types": "off", 26 | "no-console": "error" 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /scripts/utils/point-cache.js: -------------------------------------------------------------------------------- 1 | const elliptic = require("elliptic"); 2 | const ec = new elliptic.ec("secp256k1"); 3 | const BN = require("bn.js"); 4 | const { splitToRegisters } = require("./utils"); 5 | const { STRIDE, NUM_STRIDES } = require("./config"); 6 | 7 | const getPointPreComputes = point => { 8 | const keyPoint = ec.keyFromPublic({ 9 | x: Buffer.from(point.x.toString(16).padStart(64, 0), "hex"), 10 | y: Buffer.from(point.y.toString(16).padStart(64, 0), "hex") 11 | }); 12 | 13 | const gPowers = []; // [32][256][2][4] 14 | for (let i = 0n; i < NUM_STRIDES; i++) { 15 | const stride = []; 16 | const power = 2n ** (i * STRIDE); 17 | for (let j = 0n; j < 2n ** STRIDE; j++) { 18 | const l = j * power; 19 | 20 | const gPower = keyPoint.getPublic().mul(new BN(l)); 21 | 22 | const x = splitToRegisters(gPower.x); 23 | const y = splitToRegisters(gPower.y); 24 | 25 | stride.push([x, y]); 26 | } 27 | gPowers.push(stride); 28 | } 29 | 30 | return gPowers; 31 | }; 32 | 33 | module.exports = { 34 | getPointPreComputes 35 | }; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "efficient-zk-ecdsa", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "run:ecdsa_verify": "node ./scripts/build_ecdsa_verify/ecdsa_verify.js", 7 | "run:ecdsa_verify_no_precompute": "node ./scripts/build_ecdsa_verify_no_precompute/ecdsa_verify_no_precompute.js", 8 | "run:ecdsa_verify_pubkey_to_addr": "node ./scripts/build_ecdsa_verify_pubkey_to_addr/ecdsa_verify_pubkey_to_addr.js", 9 | "build:ecdsa_verify": "cd ./scripts/build_ecdsa_verify && sh ./build_ecdsa_verify.sh", 10 | "build:ecdsa_verify_no_precompute": "cd ./scripts/build_ecdsa_verify_no_precompute && sh ./build_ecdsa_verify_no_precompute.sh", 11 | "build:ecdsa_verify_pubkey_to_addr": "cd ./scripts/build_ecdsa_verify_pubkey_to_addr && sh ./build_ecdsa_verify_pubkey_to_addr.sh" 12 | }, 13 | "dependencies": { 14 | "circomlib": "^2.0.5" 15 | }, 16 | "devDependencies": { 17 | "@ethereumjs/util": "^8.0.0", 18 | "circomlibjs": "^0.1.7", 19 | "elliptic": "^6.5.4", 20 | "eslint": "^8.23.1", 21 | "prettier": "^2.7.1", 22 | "snarkjs": "^0.4.27" 23 | } 24 | } -------------------------------------------------------------------------------- /circuits/ecdsa_verify_no_precompute.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "./circom-ecdsa-circuits/secp256k1.circom"; 3 | 4 | template ECDSAVerifyNoPrecompute(n, k) { 5 | signal input s[k]; 6 | signal input T[2][k]; // T = r^-1 * R 7 | signal input U[2][k]; // -(m * r^-1 * G) 8 | signal output pubKey[2][k]; 9 | 10 | // s * T 11 | // or, s * r^-1 * R 12 | component sMultT = Secp256k1ScalarMult(n, k); 13 | var stride = 8; 14 | var num_strides = div_ceil(n * k, stride); 15 | for (var idx = 0; idx < k; idx++) { 16 | sMultT.scalar[idx] <== s[idx]; 17 | sMultT.point[0][idx] <== T[0][idx]; 18 | sMultT.point[1][idx] <== T[1][idx]; 19 | } 20 | 21 | // s * T + U 22 | // or, s * r^-1 * R + -(m * r^-1 * G) 23 | component pointAdder = Secp256k1AddUnequal(n, k); 24 | for (var i = 0; i < k; i++) { 25 | pointAdder.a[0][i] <== sMultT.out[0][i]; 26 | pointAdder.a[1][i] <== sMultT.out[1][i]; 27 | pointAdder.b[0][i] <== U[0][i]; 28 | pointAdder.b[1][i] <== U[1][i]; 29 | } 30 | 31 | for (var i = 0; i < k; i++) { 32 | pubKey[0][i] <== pointAdder.out[0][i]; 33 | pubKey[1][i] <== pointAdder.out[1][i]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /circuits/ecdsa_verify.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "./secp256k1_scalar_mult_cached_windowed.circom"; 3 | 4 | template ECDSAVerify(n, k) { 5 | signal input s[k]; 6 | signal input TPreComputes[32][256][2][4]; // T = r^-1 * R 7 | signal input U[2][k]; // -(m * r^-1 * G) 8 | signal output pubKey[2][k]; 9 | 10 | // s * T 11 | // or, s * r^-1 * R 12 | component sMultT = Secp256K1ScalarMultCachedWindowed(n, k); 13 | var stride = 8; 14 | var num_strides = div_ceil(n * k, stride); 15 | 16 | for (var i = 0; i < num_strides; i++) { 17 | for (var j = 0; j < 2 ** stride; j++) { 18 | for (var l = 0; l < k; l++) { 19 | sMultT.pointPreComputes[i][j][0][l] <== TPreComputes[i][j][0][l]; 20 | sMultT.pointPreComputes[i][j][1][l] <== TPreComputes[i][j][1][l]; 21 | } 22 | } 23 | } 24 | 25 | for (var i = 0; i < k; i++) { 26 | sMultT.scalar[i] <== s[i]; 27 | } 28 | 29 | // s * T + U 30 | // or, s * r^-1 * R + -(m * r^-1 * G) 31 | component pointAdder = Secp256k1AddUnequal(n, k); 32 | for (var i = 0; i < k; i++) { 33 | pointAdder.a[0][i] <== sMultT.out[0][i]; 34 | pointAdder.a[1][i] <== sMultT.out[1][i]; 35 | pointAdder.b[0][i] <== U[0][i]; 36 | pointAdder.b[1][i] <== U[1][i]; 37 | } 38 | 39 | for (var i = 0; i < k; i++) { 40 | pubKey[0][i] <== pointAdder.out[0][i]; 41 | pubKey[1][i] <== pointAdder.out[1][i]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /circuits/ecdsa_verify_pubkey_to_addr.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.6; 2 | include "./ecdsa_verify.circom"; 3 | include "./circom-ecdsa-circuits/zk-identity/eth.circom"; 4 | 5 | template ECDSAVerifyPubKeyToAddr(n, k) { 6 | signal input s[k]; 7 | signal input TPreComputes[32][256][2][4]; // T = r^-1 * R 8 | signal input U[2][k]; // -(m * r^-1 * G) 9 | signal output addr; 10 | 11 | component ecdsaVerify = ECDSAVerify(n, k); 12 | 13 | var stride = 8; 14 | var num_strides = div_ceil(n * k, stride); 15 | 16 | for (var i = 0; i < num_strides; i++) { 17 | for (var j = 0; j < 2 ** stride; j++) { 18 | for (var l = 0; l < k; l++) { 19 | ecdsaVerify.TPreComputes[i][j][0][l] <== TPreComputes[i][j][0][l]; 20 | ecdsaVerify.TPreComputes[i][j][1][l] <== TPreComputes[i][j][1][l]; 21 | } 22 | } 23 | } 24 | 25 | for (var i = 0; i < k; i++) { 26 | ecdsaVerify.s[i] <== s[i]; 27 | } 28 | 29 | for (var i = 0; i < k; i++) { 30 | ecdsaVerify.U[0][i] <== U[0][i]; 31 | ecdsaVerify.U[1][i] <== U[1][i]; 32 | } 33 | 34 | component flattenPub = FlattenPubkey(n, k); 35 | for (var i = 0; i < k; i++) { 36 | flattenPub.chunkedPubkey[0][i] <== ecdsaVerify.pubKey[0][i]; 37 | flattenPub.chunkedPubkey[1][i] <== ecdsaVerify.pubKey[1][i]; 38 | } 39 | 40 | component pubToAddr = PubkeyToAddress(); 41 | for (var i = 0; i < 512; i++) { 42 | pubToAddr.pubkeyBits[i] <== flattenPub.pubkeyBits[i]; 43 | } 44 | 45 | addr <== pubToAddr.address; 46 | } 47 | -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify/build_ecdsa_verify.sh: -------------------------------------------------------------------------------- 1 | CIRCUITS_DIR=../../circuits 2 | PHASE1=$CIRCUITS_DIR/pot18_final.ptau 3 | BUILD_DIR=../../build/ecdsa_verify 4 | CIRCUIT_NAME=build_ecdsa_verify 5 | 6 | if [ -f "$PHASE1" ]; then 7 | echo "Found Phase 1 ptau file" 8 | else 9 | echo "No Phase 1 ptau file found. Exiting..." 10 | exit 1 11 | fi 12 | 13 | if [ ! -d "$BUILD_DIR" ]; then 14 | echo "No build directory found. Creating build directory..." 15 | mkdir -p "$BUILD_DIR" 16 | fi 17 | 18 | echo "****COMPILING CIRCUIT****" 19 | start=`date +%s` 20 | set -x 21 | circom "./$CIRCUIT_NAME".circom --r1cs --wasm --sym --c --wat --output "$BUILD_DIR" 22 | { set +x; } 2>/dev/null 23 | end=`date +%s` 24 | echo "DONE ($((end-start))s)" 25 | 26 | echo "****GENERATING ZKEY 0****" 27 | start=`date +%s` 28 | npx snarkjs groth16 setup "$BUILD_DIR"/"$CIRCUIT_NAME".r1cs "$PHASE1" "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey 29 | end=`date +%s` 30 | echo "DONE ($((end-start))s)" 31 | 32 | echo "****GENERATING FINAL ZKEY****" 33 | start=`date +%s` 34 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey beacon "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey 12FE2EC467BD428DD0E966A6287DE2AF8DE09C2C5C0AD902B2C666B0895ABB75 10 -n="Final Beacon phase2" 35 | end=`date +%s` 36 | echo "DONE ($((end-start))s)" 37 | 38 | echo "****GENERATING VERIFICATION KEY****" 39 | start=`date +%s` 40 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey export verificationkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey "$BUILD_DIR"/verification_key.json 41 | 42 | end=`date +%s` 43 | echo "DONE ($((end-start))s)" -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify_no_precompute/build_ecdsa_verify_no_precompute.sh: -------------------------------------------------------------------------------- 1 | CIRCUITS_DIR=../../circuits 2 | PHASE1=$CIRCUITS_DIR/pot22_final.ptau 3 | BUILD_DIR=../../build/ecdsa_verify_no_precompute 4 | CIRCUIT_NAME=build_ecdsa_verify_no_precompute 5 | 6 | if [ -f "$PHASE1" ]; then 7 | echo "Found Phase 1 ptau file" 8 | else 9 | echo "No Phase 1 ptau file found. Exiting..." 10 | exit 1 11 | fi 12 | 13 | if [ ! -d "$BUILD_DIR" ]; then 14 | echo "No build directory found. Creating build directory..." 15 | mkdir -p "$BUILD_DIR" 16 | fi 17 | 18 | echo "****COMPILING CIRCUIT****" 19 | start=`date +%s` 20 | set -x 21 | circom "./$CIRCUIT_NAME".circom --r1cs --wasm --sym --c --wat --output "$BUILD_DIR" 22 | { set +x; } 2>/dev/null 23 | end=`date +%s` 24 | echo "DONE ($((end-start))s)" 25 | 26 | echo "****GENERATING ZKEY 0****" 27 | start=`date +%s` 28 | npx snarkjs groth16 setup "$BUILD_DIR"/"$CIRCUIT_NAME".r1cs "$PHASE1" "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey 29 | end=`date +%s` 30 | echo "DONE ($((end-start))s)" 31 | 32 | echo "****GENERATING FINAL ZKEY****" 33 | start=`date +%s` 34 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey beacon "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey 12FE2EC467BD428DD0E966A6287DE2AF8DE09C2C5C0AD902B2C666B0895ABB75 10 -n="Final Beacon phase2" 35 | end=`date +%s` 36 | echo "DONE ($((end-start))s)" 37 | 38 | echo "****GENERATING VERIFICATION KEY****" 39 | start=`date +%s` 40 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey export verificationkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey "$BUILD_DIR"/verification_key.json 41 | 42 | end=`date +%s` 43 | echo "DONE ($((end-start))s)" -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify_pubkey_to_addr/build_ecdsa_verify_pubkey_to_addr.sh: -------------------------------------------------------------------------------- 1 | CIRCUITS_DIR=../../circuits 2 | PHASE1=$CIRCUITS_DIR/pot20_final.ptau 3 | BUILD_DIR=../../build/ecdsa_verify_pubkey_to_addr 4 | CIRCUIT_NAME=build_ecdsa_verify_pubkey_to_addr 5 | 6 | if [ -f "$PHASE1" ]; then 7 | echo "Found Phase 1 ptau file" 8 | else 9 | echo "No Phase 1 ptau file found. Exiting..." 10 | exit 1 11 | fi 12 | 13 | if [ ! -d "$BUILD_DIR" ]; then 14 | echo "No build directory found. Creating build directory..." 15 | mkdir -p "$BUILD_DIR" 16 | fi 17 | 18 | echo "****COMPILING CIRCUIT****" 19 | start=`date +%s` 20 | set -x 21 | circom "./$CIRCUIT_NAME".circom --r1cs --wasm --sym --c --wat --output "$BUILD_DIR" 22 | { set +x; } 2>/dev/null 23 | end=`date +%s` 24 | echo "DONE ($((end-start))s)" 25 | 26 | echo "****GENERATING ZKEY 0****" 27 | start=`date +%s` 28 | npx snarkjs groth16 setup "$BUILD_DIR"/"$CIRCUIT_NAME".r1cs "$PHASE1" "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey 29 | end=`date +%s` 30 | echo "DONE ($((end-start))s)" 31 | 32 | echo "****GENERATING FINAL ZKEY****" 33 | start=`date +%s` 34 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey beacon "$BUILD_DIR"/"$CIRCUIT_NAME"_0.zkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey 12FE2EC467BD428DD0E966A6287DE2AF8DE09C2C5C0AD902B2C666B0895ABB75 10 -n="Final Beacon phase2" 35 | end=`date +%s` 36 | echo "DONE ($((end-start))s)" 37 | 38 | echo "****GENERATING VERIFICATION KEY****" 39 | start=`date +%s` 40 | NODE_OPTIONS="--max-old-space-size=56000" npx snarkjs zkey export verificationkey "$BUILD_DIR"/"$CIRCUIT_NAME".zkey "$BUILD_DIR"/verification_key.json 41 | 42 | end=`date +%s` 43 | echo "DONE ($((end-start))s)" 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # efficient-zk-ecdsa 2 | ### ⚠️ This repo is no longer maintained⚠️ 3 | ### We recommend [spartan-ecdsa](https://github.com/personaelabs/spartan-ecdsa) as a replacement 4 | 5 | 6 | 7 | 8 | _The code in this repo is unaudited and not recommended for production use._ 9 | 10 | Please refer to [this blog post](https://personaelabs.org/posts/efficient-ecdsa-1/) for details. The circuits in this repo uses circuits from [circom-ecdsa](https://github.com/0xPARC/circom-ecdsa). 11 | 12 | ## Install dependencies 13 | 14 | ``` 15 | yarn 16 | ``` 17 | 18 | ## Compile the circuit and generate the zkey 19 | 20 | ``` 21 | yarn run build:ecdsaverify 22 | ``` 23 | 24 | ## Run proof generation 25 | 26 | ``` 27 | yarn run run:ecdsaverify 28 | ``` 29 | 30 | ## Run benchmarks 31 | 32 | ``` 33 | cd ./bench 34 | ``` 35 | 36 | ``` 37 | open ./index.html 38 | ``` 39 | 40 | _The full proof and the proving time will be displayed in the browser console._ 41 | 42 | ## Benchmarks 43 | 44 | _Disclaimer: the following benchmarks are to give an intuition about the proving time of this method. We hope to run a more comprehensive benchmark across many devices soon._ 45 | 46 | ### Circuit info 47 | 48 | We include details on the circuit implementing the rearranged formula without precomputed multiples for comparison. The more precomputed multiples one uses, the larger the input size but the fewer the # of constraints. This tradeoff is relevant for any on-chain applications of this work: 49 | 50 | | Circuit | Constraints | zKey size | 51 | | --------------------------- | ----------- | --------- | 52 | | ecdsa_verify | 163,239 | 119MB | 53 | | ecdsa_verify_pubkey_to_addr | 315,175 | 197MB | 54 | | ecdsa_verify_no_precompute | 1,401,956 | 874MB | 55 | 56 | ### Browser proving 57 | 58 | _The setup_: 59 | 60 | - M1 Pro Macbook Pro 61 | - Internet speed: 40Mbps 62 | - Browser: Chrome browser 63 | 64 | | Circuit | Proving time | 65 | | --------------------------- | ------------ | 66 | | ecdsa_verify | 39.4s | 67 | | ecdsa_verify_pubkey_to_addr | 58.2s | 68 | 69 | ### Command line proving 70 | 71 | _The setup:_ 72 | 73 | - M1 Pro Macbook Pro 74 | 75 | | Circuit | Proving time | 76 | | --------------------------- | ------------ | 77 | | ecdsa_verify | 18s | 78 | | ecdsa_verify_pubkey_to_addr | 30s | 79 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/vocdoni-keccak/utils.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "../../../node_modules/circomlib/circuits/gates.circom"; 4 | include "../../../node_modules/circomlib/circuits/sha256/xor3.circom"; 5 | include "../../../node_modules/circomlib/circuits/sha256/shift.circom"; // contains ShiftRight 6 | 7 | template Xor5(n) { 8 | signal input a[n]; 9 | signal input b[n]; 10 | signal input c[n]; 11 | signal input d[n]; 12 | signal input e[n]; 13 | signal output out[n]; 14 | var i; 15 | 16 | component xor3 = Xor3(n); 17 | for (i=0; i { 19 | const vKey = JSON.parse(fs.readFileSync(VKEY_PATH)); 20 | const result = await snarkJs.groth16.verify(vKey, publicSignals, proof); 21 | if (result) { 22 | console.log("Proof verified!"); 23 | } else { 24 | console.log("Proof verification failed"); 25 | } 26 | }; 27 | 28 | const prove = async () => { 29 | if (!fs.existsSync(ZKEY_PATH)) { 30 | console.log( 31 | "zkey not found. Please run `yarn build:ecdsa_verify_no_precompute` first" 32 | ); 33 | return; 34 | } 35 | 36 | console.time("Full proof generation"); 37 | 38 | const msgHash = hashPersonalMessage(Buffer.from("hello world")); 39 | 40 | const pubKey = ec.keyFromPrivate(privKey.toString(16)).getPublic(); 41 | 42 | const { v, r, s } = ecsign(msgHash, privKey); 43 | 44 | const isYOdd = (v - BigInt(27)) % BigInt(2); 45 | const rPoint = ec.keyFromPublic( 46 | ec.curve.pointFromX(new BN(r), isYOdd).encode("hex"), 47 | "hex" 48 | ); 49 | 50 | // Get the group element: -(m * r^−1 * G) 51 | const rInv = new BN(r).invm(SECP256K1_N); 52 | 53 | // w = -(r^-1 * msg) 54 | const w = rInv.mul(new BN(msgHash)).neg().umod(SECP256K1_N); 55 | // U = -(w * G) = -(r^-1 * msg * G) 56 | const U = ec.curve.g.mul(w); 57 | 58 | // T = r^-1 * R 59 | const T = rPoint.getPublic().mul(rInv); 60 | 61 | const input = { 62 | T: [splitToRegisters(T.x), splitToRegisters(T.y)], 63 | U: [splitToRegisters(U.x), splitToRegisters(U.y)], 64 | s: [splitToRegisters(s.toString("hex"))] 65 | }; 66 | 67 | console.log("Proving..."); 68 | const { publicSignals, proof } = await snarkJs.groth16.fullProve( 69 | input, 70 | "build/ecdsa_verify_no_precompute/build_ecdsa_verify_no_precompute_js/build_ecdsa_verify_no_precompute.wasm", 71 | ZKEY_PATH 72 | ); 73 | 74 | const outputPubkeyX = registersToHex(publicSignals.slice(0, 4).reverse()); 75 | const outputPubkeyY = registersToHex(publicSignals.slice(4, 8).reverse()); 76 | const outputPubKey = `${outputPubkeyX}${outputPubkeyY}`; 77 | 78 | if (`04${outputPubKey}` === pubKey.encode("hex")) { 79 | console.log("Success!"); 80 | console.timeEnd("Full proof generation"); 81 | } else { 82 | console.log("Output public key doesn't match expected public key"); 83 | } 84 | 85 | // Now, verify the proof 86 | await verify(proof, publicSignals); 87 | 88 | process.exit(0); 89 | }; 90 | 91 | prove(); 92 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/zk-identity/eth.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "../vocdoni-keccak/keccak.circom"; 4 | 5 | include "../../../node_modules/circomlib/circuits/bitify.circom"; 6 | 7 | /* 8 | * Possibly generalizable, but for now just flatten a single pubkey from k n-bit chunks to a * single bit array 9 | * representing the entire pubkey 10 | * 11 | */ 12 | template FlattenPubkey(numBits, k) { 13 | signal input chunkedPubkey[2][k]; 14 | 15 | signal output pubkeyBits[512]; 16 | 17 | // must be able to hold entire pubkey in input 18 | assert(numBits*k >= 256); 19 | 20 | // convert pubkey to a single bit array 21 | // - concat x and y coords 22 | // - convert each register's number to corresponding bit array 23 | // - concatenate all bit arrays in order 24 | 25 | component chunks2BitsY[k]; 26 | for(var chunk = 0; chunk < k; chunk++){ 27 | chunks2BitsY[chunk] = Num2Bits(numBits); 28 | chunks2BitsY[chunk].in <== chunkedPubkey[1][chunk]; 29 | 30 | for(var bit = 0; bit < numBits; bit++){ 31 | var bitIndex = bit + numBits * chunk; 32 | if(bitIndex < 256) { 33 | pubkeyBits[bitIndex] <== chunks2BitsY[chunk].out[bit]; 34 | } 35 | } 36 | } 37 | 38 | component chunks2BitsX[k]; 39 | for(var chunk = 0; chunk < k; chunk++){ 40 | chunks2BitsX[chunk] = Num2Bits(numBits); 41 | chunks2BitsX[chunk].in <== chunkedPubkey[0][chunk]; 42 | 43 | for(var bit = 0; bit < numBits; bit++){ 44 | var bitIndex = bit + 256 + (numBits * chunk); 45 | if(bitIndex < 512) { 46 | pubkeyBits[bitIndex] <== chunks2BitsX[chunk].out[bit]; 47 | } 48 | } 49 | } 50 | } 51 | 52 | /* 53 | * Helper for verifying an eth address refers to the correct public key point 54 | * 55 | * NOTE: uses https://github.com/vocdoni/keccak256-circom, a highly experimental keccak256 implementation 56 | */ 57 | template PubkeyToAddress() { 58 | // public key is (x, y) curve point. this is a 512-bit little-endian bitstring representation of y + 2**256 * x 59 | signal input pubkeyBits[512]; 60 | 61 | signal output address; 62 | 63 | // our representation is little-endian 512-bit bitstring 64 | // keccak template operates on bytestrings one byte at a time, starting with the biggest byte 65 | // but bytes are represented as little-endian 8-bit bitstrings 66 | signal reverse[512]; 67 | 68 | for (var i = 0; i < 512; i++) { 69 | reverse[i] <== pubkeyBits[511-i]; 70 | } 71 | 72 | component keccak = Keccak(512, 256); 73 | for (var i = 0; i < 512 / 8; i += 1) { 74 | for (var j = 0; j < 8; j++) { 75 | keccak.in[8*i + j] <== reverse[8*i + (7-j)]; 76 | } 77 | } 78 | 79 | // convert the last 160 bits (20 bytes) into the number corresponding to address 80 | // the output of keccak is 32 bytes. bytes are arranged from largest to smallest 81 | // but bytes themselves are little-endian bitstrings of 8 bits 82 | // we just want a little-endian bitstring of 160 bits 83 | component bits2Num = Bits2Num(160); 84 | for (var i = 0; i < 20; i++) { 85 | for (var j = 0; j < 8; j++) { 86 | bits2Num.in[8*i + j] <== keccak.out[256 - 8*(i+1) + j]; 87 | } 88 | } 89 | 90 | address <== bits2Num.out; 91 | } -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify/ecdsa_verify.js: -------------------------------------------------------------------------------- 1 | const snarkJs = require("snarkjs"); 2 | const { hashPersonalMessage, ecsign } = require("@ethereumjs/util"); 3 | const { SECP256K1_N } = require("../utils/config"); 4 | const elliptic = require("elliptic"); 5 | const ec = new elliptic.ec("secp256k1"); 6 | const BN = require("bn.js"); 7 | const { splitToRegisters, registersToHex } = require("../utils/utils"); 8 | const fs = require("fs"); 9 | const { getPointPreComputes } = require("../utils/point-cache"); 10 | 11 | const privKey = BigInt( 12 | "0xf5b552f608f5b552f608f5b552f6082ff5b552f608f5b552f608f5b552f6082f" 13 | ); 14 | 15 | const ZKEY_PATH = "build/ecdsa_verify/build_ecdsa_verify.zkey"; 16 | const VKEY_PATH = "build/ecdsa_verify/verification_key.json"; 17 | 18 | const verify = async (proof, publicSignals) => { 19 | const vKey = JSON.parse(fs.readFileSync(VKEY_PATH)); 20 | const result = await snarkJs.groth16.verify(vKey, publicSignals, proof); 21 | if (result) { 22 | console.log("Proof verified!"); 23 | } else { 24 | console.log("Proof verification failed"); 25 | } 26 | }; 27 | 28 | const prove = async () => { 29 | if (!fs.existsSync(ZKEY_PATH)) { 30 | console.log("zkey not found. Please run `yarn build:ecdsa_verify` first"); 31 | return; 32 | } 33 | 34 | console.time("Full proof generation"); 35 | 36 | const msgHash = hashPersonalMessage(Buffer.from("hello world")); 37 | 38 | const pubKey = ec.keyFromPrivate(privKey.toString(16)).getPublic(); 39 | 40 | const { v, r, s } = ecsign(msgHash, privKey); 41 | 42 | const isYOdd = (v - BigInt(27)) % BigInt(2); 43 | const rPoint = ec.keyFromPublic( 44 | ec.curve.pointFromX(new BN(r), isYOdd).encode("hex"), 45 | "hex" 46 | ); 47 | 48 | // Get the group element: -(m * r^−1 * G) 49 | const rInv = new BN(r).invm(SECP256K1_N); 50 | 51 | // w = -(r^-1 * msg) 52 | const w = rInv.mul(new BN(msgHash)).neg().umod(SECP256K1_N); 53 | // U = -(w * G) = -(r^-1 * msg * G) 54 | const U = ec.curve.g.mul(w); 55 | 56 | // T = r^-1 * R 57 | const T = rPoint.getPublic().mul(rInv); 58 | 59 | console.log("Calculating point cache..."); 60 | console.time("Point cache calculation"); 61 | const TPreComputes = getPointPreComputes(T); 62 | console.timeEnd("Point cache calculation"); 63 | 64 | const input = { 65 | TPreComputes, 66 | U: [splitToRegisters(U.x), splitToRegisters(U.y)], 67 | s: [splitToRegisters(s.toString("hex"))] 68 | }; 69 | 70 | console.log("Proving..."); 71 | const { publicSignals, proof } = await snarkJs.groth16.fullProve( 72 | input, 73 | "build/ecdsa_verify/build_ecdsa_verify_js/build_ecdsa_verify.wasm", 74 | ZKEY_PATH 75 | ); 76 | 77 | const outputPubkeyX = registersToHex(publicSignals.slice(0, 4).reverse()); 78 | const outputPubkeyY = registersToHex(publicSignals.slice(4, 8).reverse()); 79 | const outputPubKey = `${outputPubkeyX}${outputPubkeyY}`; 80 | 81 | if (`04${outputPubKey}` === pubKey.encode("hex")) { 82 | console.log("Success!"); 83 | console.timeEnd("Full proof generation"); 84 | } else { 85 | console.log("Output public key doesn't match expected public key"); 86 | } 87 | 88 | // Now, verify the proof 89 | await verify(proof, publicSignals); 90 | 91 | process.exit(0); 92 | }; 93 | 94 | prove(); 95 | -------------------------------------------------------------------------------- /scripts/build_ecdsa_verify_pubkey_to_addr/ecdsa_verify_pubkey_to_addr.js: -------------------------------------------------------------------------------- 1 | const snarkJs = require("snarkjs"); 2 | const { 3 | hashPersonalMessage, 4 | ecsign, 5 | publicToAddress 6 | } = require("@ethereumjs/util"); 7 | const { SECP256K1_N } = require("../utils/config"); 8 | const elliptic = require("elliptic"); 9 | const ec = new elliptic.ec("secp256k1"); 10 | const BN = require("bn.js"); 11 | const { splitToRegisters, registersToHex } = require("../utils/utils"); 12 | const fs = require("fs"); 13 | const { getPointPreComputes } = require("../utils/point-cache"); 14 | 15 | const privKey = BigInt( 16 | "0xf5b552f608f5b552f608f5b552f6082ff5b552f608f5b552f608f5b552f6082f" 17 | ); 18 | 19 | const ZKEY_PATH = 20 | "build/ecdsa_verify_pubkey_to_addr/build_ecdsa_verify_pubkey_to_addr.zkey"; 21 | const VKEY_PATH = "build/ecdsa_verify_pubkey_to_addr/verification_key.json"; 22 | 23 | const verify = async (proof, publicSignals) => { 24 | const vKey = JSON.parse(fs.readFileSync(VKEY_PATH)); 25 | const result = await snarkJs.groth16.verify( 26 | vKey, 27 | publicSignals, 28 | proof, 29 | console 30 | ); 31 | 32 | if (result) { 33 | console.log("Proof verified!"); 34 | } else { 35 | console.log("Proof verification failed"); 36 | } 37 | }; 38 | 39 | const prove = async () => { 40 | if (!fs.existsSync(ZKEY_PATH)) { 41 | console.log( 42 | "zkey not found. Please run `yarn build:ecdsa_verify_pubkey_to_addr` first" 43 | ); 44 | return; 45 | } 46 | 47 | console.time("Full proof generation"); 48 | 49 | const msgHash = hashPersonalMessage(Buffer.from("hello world")); 50 | 51 | const pubKey = ec.keyFromPrivate(privKey.toString(16)).getPublic(); 52 | 53 | const address = BigInt( 54 | `0x${publicToAddress( 55 | Buffer.from(pubKey.encode("hex").substring(2), "hex") 56 | ).toString("hex")}` 57 | ); 58 | 59 | const { v, r, s } = ecsign(msgHash, privKey); 60 | 61 | const isYOdd = (v - BigInt(27)) % BigInt(2); 62 | const rPoint = ec.keyFromPublic( 63 | ec.curve.pointFromX(new BN(r), isYOdd).encode("hex"), 64 | "hex" 65 | ); 66 | 67 | // Get the group element: -(m * r^−1 * G) 68 | const rInv = new BN(r).invm(SECP256K1_N); 69 | 70 | // w = -(r^-1 * msg) 71 | const w = rInv.mul(new BN(msgHash)).neg().umod(SECP256K1_N); 72 | // U = -(w * G) = -(r^-1 * msg * G) 73 | const U = ec.curve.g.mul(w); 74 | 75 | // T = r^-1 * R 76 | const T = rPoint.getPublic().mul(rInv); 77 | 78 | console.log("Calculating point cache..."); 79 | console.time("Point cache calculation"); 80 | const TPreComputes = getPointPreComputes(T); 81 | console.timeEnd("Point cache calculation"); 82 | 83 | const input = { 84 | TPreComputes, 85 | U: [splitToRegisters(U.x), splitToRegisters(U.y)], 86 | s: [splitToRegisters(s.toString("hex"))] 87 | }; 88 | 89 | console.log("Proving..."); 90 | const { publicSignals, proof } = await snarkJs.groth16.fullProve( 91 | input, 92 | "build/ecdsa_verify_pubkey_to_addr/build_ecdsa_verify_pubkey_to_addr_js/build_ecdsa_verify_pubkey_to_addr.wasm", 93 | ZKEY_PATH 94 | ); 95 | 96 | const outputAddress = publicSignals[0]; 97 | 98 | if (outputAddress === address.toString(10)) { 99 | console.log("Success!"); 100 | console.timeEnd("Full proof generation"); 101 | } else { 102 | console.log("Output address doesn't match the expected address"); 103 | } 104 | 105 | // Now, verify the proof 106 | await verify(proof, publicSignals); 107 | 108 | process.exit(0); 109 | }; 110 | 111 | prove(); 112 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/vocdoni-keccak/keccak.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "./utils.circom"; 4 | include "./permutations.circom"; 5 | 6 | template Pad(nBits) { 7 | signal input in[nBits]; 8 | 9 | var blockSize=136*8; 10 | signal output out[blockSize]; 11 | signal out2[blockSize]; 12 | 13 | var i; 14 | 15 | for (i=0; i> i) & 1; 21 | } 22 | for (i=nBits+8; i> i) & 1; 29 | } 30 | for (i=0; i<8; i++) { 31 | out[blockSize-8+i] <== aux.out[i]; 32 | } 33 | for (i=0; i 208 bits 7 | // input registers can also be negative; the overall input can be negative as well 8 | template Secp256k1PrimeReduce10Registers() { 9 | signal input in[10]; 10 | 11 | signal output out[4]; 12 | var offset = (1<<32) + 977; // 33 bits 13 | var offset2 = ((1<<33) * 977) + (977 ** 2); // 43 bits 14 | 15 | out[3] <== (offset * in[7]) + in[3]; 16 | out[2] <== (offset * in[6]) + in[2] + in[9]; 17 | out[1] <== (offset2 * in[9]) + (offset * in[5]) + in[1] + in[8]; 18 | out[0] <== (offset2 * in[8]) + (offset * in[4]) + in[0]; 19 | } 20 | 21 | // 7 registers, 64 bits. registers can be overful 22 | // adds 33 bits to overflow, so don't input overful registers which are > 218 bits 23 | // input registers can also be negative; the overall input can be negative as well 24 | template Secp256k1PrimeReduce7Registers() { 25 | signal input in[7]; 26 | 27 | signal output out[4]; 28 | var offset = (1<<32) + 977; // 33 bits 29 | 30 | out[3] <== in[3]; 31 | out[2] <== (offset * in[6]) + in[2]; 32 | out[1] <== (offset * in[5]) + in[1]; 33 | out[0] <== (offset * in[4]) + in[0]; 34 | } 35 | 36 | template CheckInRangeSecp256k1 () { 37 | signal input in[4]; 38 | component range64[4]; 39 | for(var i = 0; i < 4; i++){ 40 | range64[i] = Num2Bits(64); 41 | range64[i].in <== in[i]; 42 | } 43 | component isEqual[3]; 44 | signal allEqual[4]; 45 | allEqual[0] <== 1; 46 | for(var i = 1; i < 4; i++){ 47 | isEqual[i-1] = IsEqual(); 48 | isEqual[i-1].in[0] <== in[i]; 49 | isEqual[i-1].in[1] <== (1<<64)-1; 50 | allEqual[i] <== allEqual[i-1] * isEqual[i-1].out; 51 | } 52 | signal c; 53 | c <== (1<<64) - ((1<<32) + (1<<9) + (1<<8) + (1<<7) + (1<<6) + (1<<4) + 1); 54 | //lowest register is less than c 55 | component lessThan = LessThan(64); 56 | lessThan.in[0] <== in[0]; 57 | lessThan.in[1] <== c; 58 | (1-lessThan.out) * allEqual[3] === 0; 59 | } 60 | 61 | // 64 bit registers with m-bit overflow 62 | // registers (and overall number) are potentially negative 63 | template CheckCubicModPIsZero(m) { 64 | assert(m < 206); // since we deal with up to m+46 bit, potentially negative registers 65 | 66 | signal input in[10]; 67 | 68 | // the secp256k1 field size, hardcoded 69 | signal p[4]; 70 | p[0] <== 18446744069414583343; 71 | p[1] <== 18446744073709551615; 72 | p[2] <== 18446744073709551615; 73 | p[3] <== 18446744073709551615; 74 | 75 | // now, we compute a positive number congruent to `in` expressible in 4 overflowed registers. 76 | // for this representation, individual registers are allowed to be negative, but the final number 77 | // will be nonnegative overall. 78 | // first, we apply the secp 10-register reduction technique to reduce to 4 registers. this may result 79 | // in a negative number overall, but preserves congruence mod p. 80 | // our intermediate result is z = secpReduce(in) 81 | // second, we add a big multiple of p to z, to ensure that our final result is positive. 82 | // since the registers of z are m + 43 bits, its max abs value is 2^(m+43 + 192) + 2^(m+43 + 128) + ... 83 | // so we add p * 2^(m-20), which is a bit under 2^(m+236) and larger than |z| < 2^(m+43+192) + eps 84 | signal reduced[4]; 85 | component secpReducer = Secp256k1PrimeReduce10Registers(); 86 | for (var i = 0; i < 10; i++) { 87 | secpReducer.in[i] <== in[i]; 88 | } 89 | signal multipleOfP[4]; 90 | for (var i = 0; i < 4; i++) { 91 | multipleOfP[i] <== p[i] * (1 << (m-20)); // m - 20 + 64 = m+44 bits 92 | } 93 | for (var i = 0; i < 4; i++) { 94 | reduced[i] <== secpReducer.out[i] + multipleOfP[i]; // max(m+43, m+44) + 1 = m+45 bits 95 | } 96 | 97 | // now we compute the quotient q, which serves as a witness. we can do simple bounding to show 98 | // that the the expected quotient is always expressible in 3 registers (i.e. < 2^192) 99 | // so long as m < 211 100 | signal q[3]; 101 | 102 | var temp[100] = getProperRepresentation(m + 45, 64, 4, reduced); 103 | var proper[8]; 104 | for (var i = 0; i < 8; i++) { 105 | proper[i] = temp[i]; 106 | } 107 | 108 | var qVarTemp[2][100] = long_div(64, 4, 4, proper, p); 109 | for (var i = 0; i < 3; i++) { 110 | q[i] <-- qVarTemp[0][i]; 111 | } 112 | 113 | // we need to constrain that q is in proper (3x64) representation 114 | component qRangeChecks[3]; 115 | for (var i = 0; i < 3; i++) { 116 | qRangeChecks[i] = Num2Bits(64); 117 | qRangeChecks[i].in <== q[i]; 118 | } 119 | 120 | // now we compute a representation qpProd = q * p 121 | signal qpProd[6]; 122 | component qpProdComp = BigMultNoCarry(64, 64, 64, 3, 4); 123 | for (var i = 0; i < 3; i++) { 124 | qpProdComp.a[i] <== q[i]; 125 | } 126 | for (var i = 0; i < 4; i++) { 127 | qpProdComp.b[i] <== p[i]; 128 | } 129 | for (var i = 0; i < 6; i++) { 130 | qpProd[i] <== qpProdComp.out[i]; // 130 bits 131 | } 132 | 133 | // finally, check that qpProd == reduced 134 | component zeroCheck = CheckCarryToZero(64, m + 46, 6); 135 | for (var i = 0; i < 6; i++) { 136 | if (i < 4) { // reduced only has 4 registers 137 | zeroCheck.in[i] <== qpProd[i] - reduced[i]; // (m + 45) + 1 bits 138 | } else { 139 | zeroCheck.in[i] <== qpProd[i]; 140 | } 141 | } 142 | } 143 | 144 | // 64 bit registers with m-bit overflow 145 | // registers (and overall number) are potentially negative 146 | template CheckQuadraticModPIsZero(m) { 147 | assert(m < 147); // so that we can assume q has 2 registers 148 | 149 | signal input in[7]; 150 | 151 | // the secp256k1 field size, hardcoded 152 | signal p[4]; 153 | p[0] <== 18446744069414583343; 154 | p[1] <== 18446744073709551615; 155 | p[2] <== 18446744073709551615; 156 | p[3] <== 18446744073709551615; 157 | 158 | // now, we compute a positive number congruent to `in` expressible in 4 overflowed registers. 159 | // for this representation, individual registers are allowed to be negative, but the final number 160 | // will be nonnegative overall. 161 | // first, we apply the secp 7-register reduction technique to reduce to 4 registers. this may result 162 | // in a negative number overall, but preserves congruence mod p. 163 | // our intermediate result is z = secpReduce(in) 164 | // second, we add a big multiple of p to z, to ensure that our final result is positive. 165 | // since the registers of z are m + 33 bits, its max abs value is 2^(m+33 + 192) + 2^(m+33 + 128) + ... 166 | // so we add p * 2^(m-30), which is a bit under 2^(m+226) and larger than |z| < 2^(m+33+192) + eps 167 | signal reduced[4]; 168 | component secpReducer = Secp256k1PrimeReduce7Registers(); 169 | for (var i = 0; i < 7; i++) { 170 | secpReducer.in[i] <== in[i]; 171 | } 172 | signal multipleOfP[4]; 173 | for (var i = 0; i < 4; i++) { 174 | multipleOfP[i] <== p[i] * (1 << (m-30)); // m - 30 + 64 = m + 34 bits 175 | } 176 | for (var i = 0; i < 4; i++) { 177 | reduced[i] <== secpReducer.out[i] + multipleOfP[i]; // max(m+33, m+34) + 1 = m+35 bits 178 | } 179 | 180 | // now we compute the quotient q, which serves as a witness. we can do simple bounding to show 181 | // that the the expected quotient is always expressible in 2 registers (i.e. < 2^192) 182 | // so long as m < 147 183 | signal q[2]; 184 | 185 | var temp[100] = getProperRepresentation(m + 35, 64, 4, reduced); 186 | var proper[8]; 187 | for (var i = 0; i < 8; i++) { 188 | proper[i] = temp[i]; 189 | } 190 | 191 | var qVarTemp[2][100] = long_div(64, 4, 4, proper, p); 192 | for (var i = 0; i < 2; i++) { 193 | q[i] <-- qVarTemp[0][i]; 194 | } 195 | 196 | // we need to constrain that q is in proper (2x64) representation 197 | component qRangeChecks[2]; 198 | for (var i = 0; i < 2; i++) { 199 | qRangeChecks[i] = Num2Bits(64); 200 | qRangeChecks[i].in <== q[i]; 201 | } 202 | 203 | // now we compute a representation qpProd = q * p 204 | signal qpProd[5]; 205 | component qpProdComp = BigMultNoCarry(64, 64, 64, 2, 4); 206 | for (var i = 0; i < 2; i++) { 207 | qpProdComp.a[i] <== q[i]; 208 | } 209 | for (var i = 0; i < 4; i++) { 210 | qpProdComp.b[i] <== p[i]; 211 | } 212 | for (var i = 0; i < 5; i++) { 213 | qpProd[i] <== qpProdComp.out[i]; // 130 bits 214 | } 215 | 216 | // finally, check that qpProd == reduced 217 | component zeroCheck = CheckCarryToZero(64, m + 36, 5); 218 | for (var i = 0; i < 5; i++) { 219 | if (i < 4) { // reduced only has 4 registers 220 | zeroCheck.in[i] <== qpProd[i] - reduced[i]; // (m + 35) + 1 bits 221 | } else { 222 | zeroCheck.in[i] <== qpProd[i]; 223 | } 224 | } 225 | } -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/ecdsa.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "../../node_modules/circomlib/circuits/comparators.circom"; 4 | include "../../node_modules/circomlib/circuits/multiplexer.circom"; 5 | 6 | include "bigint.circom"; 7 | include "secp256k1.circom"; 8 | include "bigint_func.circom"; 9 | include "ecdsa_func.circom"; 10 | include "secp256k1_func.circom"; 11 | 12 | // keys are encoded as (x, y) pairs with each coordinate being 13 | // encoded with k registers of n bits each 14 | template ECDSAPrivToPub(n, k) { 15 | var stride = 8; 16 | signal input privkey[k]; 17 | signal output pubkey[2][k]; 18 | 19 | component n2b[k]; 20 | for (var i = 0; i < k; i++) { 21 | n2b[i] = Num2Bits(n); 22 | n2b[i].in <== privkey[i]; 23 | } 24 | 25 | var num_strides = div_ceil(n * k, stride); 26 | // power[i][j] contains: [j * (1 << stride * i) * G] for 1 <= j < (1 << stride) 27 | var powers[num_strides][2 ** stride][2][k]; 28 | powers = get_g_pow_stride8_table(n, k); 29 | 30 | // contains a dummy point G * 2 ** 255 to stand in when we are adding 0 31 | // this point is sometimes an input into AddUnequal, so it must be guaranteed 32 | // to never equal any possible partial sum that we might get 33 | var dummyHolder[2][100] = get_dummy_point(n, k); 34 | var dummy[2][k]; 35 | for (var i = 0; i < k; i++) dummy[0][i] = dummyHolder[0][i]; 36 | for (var i = 0; i < k; i++) dummy[1][i] = dummyHolder[1][i]; 37 | 38 | // selector[i] contains a value in [0, ..., 2**i - 1] 39 | component selectors[num_strides]; 40 | for (var i = 0; i < num_strides; i++) { 41 | selectors[i] = Bits2Num(stride); 42 | for (var j = 0; j < stride; j++) { 43 | var bit_idx1 = (i * stride + j) \ n; 44 | var bit_idx2 = (i * stride + j) % n; 45 | if (bit_idx1 < k) { 46 | selectors[i].in[j] <== n2b[bit_idx1].out[bit_idx2]; 47 | } else { 48 | selectors[i].in[j] <== 0; 49 | } 50 | } 51 | } 52 | 53 | // multiplexers[i][l].out will be the coordinates of: 54 | // selectors[i].out * (2 ** (i * stride)) * G if selectors[i].out is non-zero 55 | // (2 ** 255) * G if selectors[i].out is zero 56 | component multiplexers[num_strides][2]; 57 | // select from k-register outputs using a 2 ** stride bit selector 58 | for (var i = 0; i < num_strides; i++) { 59 | for (var l = 0; l < 2; l++) { 60 | multiplexers[i][l] = Multiplexer(k, (1 << stride)); 61 | multiplexers[i][l].sel <== selectors[i].out; 62 | for (var idx = 0; idx < k; idx++) { 63 | multiplexers[i][l].inp[0][idx] <== dummy[l][idx]; 64 | for (var j = 1; j < (1 << stride); j++) { 65 | multiplexers[i][l].inp[j][idx] <== powers[i][j][l][idx]; 66 | } 67 | } 68 | } 69 | } 70 | 71 | component iszero[num_strides]; 72 | for (var i = 0; i < num_strides; i++) { 73 | iszero[i] = IsZero(); 74 | iszero[i].in <== selectors[i].out; 75 | } 76 | 77 | // has_prev_nonzero[i] = 1 if at least one of the selections in privkey up to stride i is non-zero 78 | component has_prev_nonzero[num_strides]; 79 | has_prev_nonzero[0] = OR(); 80 | has_prev_nonzero[0].a <== 0; 81 | has_prev_nonzero[0].b <== 1 - iszero[0].out; 82 | for (var i = 1; i < num_strides; i++) { 83 | has_prev_nonzero[i] = OR(); 84 | has_prev_nonzero[i].a <== has_prev_nonzero[i - 1].out; 85 | has_prev_nonzero[i].b <== 1 - iszero[i].out; 86 | } 87 | 88 | signal partial[num_strides][2][k]; 89 | for (var idx = 0; idx < k; idx++) { 90 | for (var l = 0; l < 2; l++) { 91 | partial[0][l][idx] <== multiplexers[0][l].out[idx]; 92 | } 93 | } 94 | 95 | component adders[num_strides - 1]; 96 | signal intermed1[num_strides - 1][2][k]; 97 | signal intermed2[num_strides - 1][2][k]; 98 | for (var i = 1; i < num_strides; i++) { 99 | adders[i - 1] = Secp256k1AddUnequal(n, k); 100 | for (var idx = 0; idx < k; idx++) { 101 | for (var l = 0; l < 2; l++) { 102 | adders[i - 1].a[l][idx] <== partial[i - 1][l][idx]; 103 | adders[i - 1].b[l][idx] <== multiplexers[i][l].out[idx]; 104 | } 105 | } 106 | 107 | // partial[i] = has_prev_nonzero[i - 1] * ((1 - iszero[i]) * adders[i - 1].out + iszero[i] * partial[i - 1][0][idx]) 108 | // + (1 - has_prev_nonzero[i - 1]) * (1 - iszero[i]) * multiplexers[i] 109 | for (var idx = 0; idx < k; idx++) { 110 | for (var l = 0; l < 2; l++) { 111 | intermed1[i - 1][l][idx] <== iszero[i].out * (partial[i - 1][l][idx] - adders[i - 1].out[l][idx]) + adders[i - 1].out[l][idx]; 112 | intermed2[i - 1][l][idx] <== multiplexers[i][l].out[idx] - iszero[i].out * multiplexers[i][l].out[idx]; 113 | partial[i][l][idx] <== has_prev_nonzero[i - 1].out * (intermed1[i - 1][l][idx] - intermed2[i - 1][l][idx]) + intermed2[i - 1][l][idx]; 114 | } 115 | } 116 | } 117 | 118 | for (var i = 0; i < k; i++) { 119 | for (var l = 0; l < 2; l++) { 120 | pubkey[l][i] <== partial[num_strides - 1][l][i]; 121 | } 122 | } 123 | } 124 | 125 | // r, s, msghash, and pubkey have coordinates 126 | // encoded with k registers of n bits each 127 | // signature is (r, s) 128 | // Does not check that pubkey is valid 129 | template ECDSAVerifyNoPubkeyCheck(n, k) { 130 | assert(k >= 2); 131 | assert(k <= 100); 132 | 133 | signal input r[k]; 134 | signal input s[k]; 135 | signal input msghash[k]; 136 | signal input pubkey[2][k]; 137 | 138 | signal output result; 139 | 140 | var p[100] = get_secp256k1_prime(n, k); 141 | var order[100] = get_secp256k1_order(n, k); 142 | 143 | // compute multiplicative inverse of s mod n 144 | var sinv_comp[100] = mod_inv(n, k, s, order); 145 | signal sinv[k]; 146 | component sinv_range_checks[k]; 147 | for (var idx = 0; idx < k; idx++) { 148 | sinv[idx] <-- sinv_comp[idx]; 149 | sinv_range_checks[idx] = Num2Bits(n); 150 | sinv_range_checks[idx].in <== sinv[idx]; 151 | } 152 | component sinv_check = BigMultModP(n, k); 153 | for (var idx = 0; idx < k; idx++) { 154 | sinv_check.a[idx] <== sinv[idx]; 155 | sinv_check.b[idx] <== s[idx]; 156 | sinv_check.p[idx] <== order[idx]; 157 | } 158 | for (var idx = 0; idx < k; idx++) { 159 | if (idx > 0) { 160 | sinv_check.out[idx] === 0; 161 | } 162 | if (idx == 0) { 163 | sinv_check.out[idx] === 1; 164 | } 165 | } 166 | 167 | // compute (h * sinv) mod n 168 | component g_coeff = BigMultModP(n, k); 169 | for (var idx = 0; idx < k; idx++) { 170 | g_coeff.a[idx] <== sinv[idx]; 171 | g_coeff.b[idx] <== msghash[idx]; 172 | g_coeff.p[idx] <== order[idx]; 173 | } 174 | 175 | // compute (h * sinv) * G 176 | component g_mult = ECDSAPrivToPub(n, k); 177 | for (var idx = 0; idx < k; idx++) { 178 | g_mult.privkey[idx] <== g_coeff.out[idx]; 179 | } 180 | 181 | // compute (r * sinv) mod n 182 | component pubkey_coeff = BigMultModP(n, k); 183 | for (var idx = 0; idx < k; idx++) { 184 | pubkey_coeff.a[idx] <== sinv[idx]; 185 | pubkey_coeff.b[idx] <== r[idx]; 186 | pubkey_coeff.p[idx] <== order[idx]; 187 | } 188 | 189 | // compute (r * sinv) * pubkey 190 | component pubkey_mult = Secp256k1ScalarMult(n, k); 191 | for (var idx = 0; idx < k; idx++) { 192 | pubkey_mult.scalar[idx] <== pubkey_coeff.out[idx]; 193 | pubkey_mult.point[0][idx] <== pubkey[0][idx]; 194 | pubkey_mult.point[1][idx] <== pubkey[1][idx]; 195 | } 196 | 197 | // compute (h * sinv) * G + (r * sinv) * pubkey 198 | component sum_res = Secp256k1AddUnequal(n, k); 199 | for (var idx = 0; idx < k; idx++) { 200 | sum_res.a[0][idx] <== g_mult.pubkey[0][idx]; 201 | sum_res.a[1][idx] <== g_mult.pubkey[1][idx]; 202 | sum_res.b[0][idx] <== pubkey_mult.out[0][idx]; 203 | sum_res.b[1][idx] <== pubkey_mult.out[1][idx]; 204 | } 205 | 206 | // compare sum_res.x with r 207 | component compare[k]; 208 | signal num_equal[k - 1]; 209 | for (var idx = 0; idx < k; idx++) { 210 | compare[idx] = IsEqual(); 211 | compare[idx].in[0] <== r[idx]; 212 | compare[idx].in[1] <== sum_res.out[0][idx]; 213 | 214 | if (idx > 0) { 215 | if (idx == 1) { 216 | num_equal[idx - 1] <== compare[0].out + compare[1].out; 217 | } else { 218 | num_equal[idx - 1] <== num_equal[idx - 2] + compare[idx].out; 219 | } 220 | } 221 | } 222 | component res_comp = IsEqual(); 223 | res_comp.in[0] <== k; 224 | res_comp.in[1] <== num_equal[k - 2]; 225 | result <== res_comp.out; 226 | } 227 | 228 | // TODO: implement ECDSA extended verify 229 | // r, s, and msghash have coordinates 230 | // encoded with k registers of n bits each 231 | // v is a single bit 232 | // extended signature is (r, s, v) 233 | template ECDSAExtendedVerify(n, k) { 234 | signal input r[k]; 235 | signal input s[k]; 236 | signal input v; 237 | signal input msghash[k]; 238 | 239 | signal output result; 240 | } 241 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/bigint_func.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | function isNegative(x) { 4 | // half babyjubjub field size 5 | return x > 10944121435919637611123202872628637544274182200208017171849102093287904247808 ? 1 : 0; 6 | } 7 | 8 | function div_ceil(m, n) { 9 | var ret = 0; 10 | if (m % n == 0) { 11 | ret = m \ n; 12 | } else { 13 | ret = m \ n + 1; 14 | } 15 | return ret; 16 | } 17 | 18 | function log_ceil(n) { 19 | var n_temp = n; 20 | for (var i = 0; i < 254; i++) { 21 | if (n_temp == 0) { 22 | return i; 23 | } 24 | n_temp = n_temp \ 2; 25 | } 26 | return 254; 27 | } 28 | 29 | function SplitFn(in, n, m) { 30 | return [in % (1 << n), (in \ (1 << n)) % (1 << m)]; 31 | } 32 | 33 | function SplitThreeFn(in, n, m, k) { 34 | return [in % (1 << n), (in \ (1 << n)) % (1 << m), (in \ (1 << n + m)) % (1 << k)]; 35 | } 36 | 37 | // in is an m bit number 38 | // split into ceil(m/n) n-bit registers 39 | function splitOverflowedRegister(m, n, in) { 40 | var out[100]; 41 | 42 | for (var i = 0; i < 100; i++) { 43 | out[i] = 0; 44 | } 45 | 46 | var nRegisters = div_ceil(m, n); 47 | var running = in; 48 | for (var i = 0; i < nRegisters; i++) { 49 | out[i] = running % (1<>=n; 51 | } 52 | 53 | return out; 54 | } 55 | 56 | // m bits per overflowed register (values are potentially negative) 57 | // n bits per properly-sized register 58 | // in has k registers 59 | // out has k + ceil(m/n) - 1 + 1 registers. highest-order potentially negative, 60 | // all others are positive 61 | // - 1 since the last register is included in the last ceil(m/n) array 62 | // + 1 since the carries from previous registers could push you over 63 | function getProperRepresentation(m, n, k, in) { 64 | var ceilMN = 0; // ceil(m/n) 65 | if (m % n == 0) { 66 | ceilMN = m \ n; 67 | } else { 68 | ceilMN = m \ n + 1; 69 | } 70 | 71 | var pieces[100][100]; // should be pieces[k][ceilMN] 72 | for (var i = 0; i < k; i++) { 73 | for (var j = 0; j < 100; j++) { 74 | pieces[i][j] = 0; 75 | } 76 | if (isNegative(in[i]) == 1) { 77 | var negPieces[100] = splitOverflowedRegister(m, n, -1 * in[i]); 78 | for (var j = 0; j < ceilMN; j++) { 79 | pieces[i][j] = -1 * negPieces[j]; 80 | } 81 | } else { 82 | pieces[i] = splitOverflowedRegister(m, n, in[i]); 83 | } 84 | } 85 | 86 | var out[100]; // should be out[k + ceilMN] 87 | var carries[100]; // should be carries[k + ceilMN] 88 | for (var i = 0; i < 100; i++) { 89 | out[i] = 0; 90 | carries[i] = 0; 91 | } 92 | for (var registerIdx = 0; registerIdx < k + ceilMN; registerIdx++) { 93 | var thisRegisterValue = 0; 94 | if (registerIdx > 0) { 95 | thisRegisterValue = carries[registerIdx - 1]; 96 | } 97 | 98 | var start = 0; 99 | if (registerIdx >= ceilMN) { 100 | start = registerIdx - ceilMN + 1; 101 | } 102 | 103 | // go from start to min(registerIdx, len(pieces)-1) 104 | for (var i = start; i <= registerIdx; i++) { 105 | if (i < k) { 106 | thisRegisterValue += pieces[i][registerIdx - i]; 107 | } 108 | } 109 | 110 | if (isNegative(thisRegisterValue) == 1) { 111 | var thisRegisterAbs = -1 * thisRegisterValue; 112 | out[registerIdx] = (1<> n) - 1; 114 | } else { 115 | out[registerIdx] = thisRegisterValue % (1<> n; 117 | } 118 | } 119 | 120 | return out; 121 | } 122 | 123 | // 1 if true, 0 if false 124 | function long_gt(n, k, a, b) { 125 | for (var i = k - 1; i >= 0; i--) { 126 | if (a[i] > b[i]) { 127 | return 1; 128 | } 129 | if (a[i] < b[i]) { 130 | return 0; 131 | } 132 | } 133 | return 0; 134 | } 135 | 136 | // n bits per register 137 | // a has k registers 138 | // b has k registers 139 | // a >= b 140 | function long_sub(n, k, a, b) { 141 | var diff[100]; 142 | var borrow[100]; 143 | for (var i = 0; i < k; i++) { 144 | if (i == 0) { 145 | if (a[i] >= b[i]) { 146 | diff[i] = a[i] - b[i]; 147 | borrow[i] = 0; 148 | } else { 149 | diff[i] = a[i] - b[i] + (1 << n); 150 | borrow[i] = 1; 151 | } 152 | } else { 153 | if (a[i] >= b[i] + borrow[i - 1]) { 154 | diff[i] = a[i] - b[i] - borrow[i - 1]; 155 | borrow[i] = 0; 156 | } else { 157 | diff[i] = (1 << n) + a[i] - b[i] - borrow[i - 1]; 158 | borrow[i] = 1; 159 | } 160 | } 161 | } 162 | return diff; 163 | } 164 | 165 | // a is a n-bit scalar 166 | // b has k registers 167 | function long_scalar_mult(n, k, a, b) { 168 | var out[100]; 169 | for (var i = 0; i < 100; i++) { 170 | out[i] = 0; 171 | } 172 | for (var i = 0; i < k; i++) { 173 | var temp = out[i] + (a * b[i]); 174 | out[i] = temp % (1 << n); 175 | out[i + 1] = out[i + 1] + temp \ (1 << n); 176 | } 177 | return out; 178 | } 179 | 180 | 181 | // n bits per register 182 | // a has k + m registers 183 | // b has k registers 184 | // out[0] has length m + 1 -- quotient 185 | // out[1] has length k -- remainder 186 | // implements algorithm of https://people.eecs.berkeley.edu/~fateman/282/F%20Wright%20notes/week4.pdf 187 | // b[k-1] must be nonzero! 188 | function long_div(n, k, m, a, b){ 189 | var out[2][100]; 190 | 191 | var remainder[200]; 192 | for (var i = 0; i < m + k; i++) { 193 | remainder[i] = a[i]; 194 | } 195 | 196 | var mult[200]; 197 | var dividend[200]; 198 | for (var i = m; i >= 0; i--) { 199 | if (i == m) { 200 | dividend[k] = 0; 201 | for (var j = k - 1; j >= 0; j--) { 202 | dividend[j] = remainder[j + m]; 203 | } 204 | } else { 205 | for (var j = k; j >= 0; j--) { 206 | dividend[j] = remainder[j + i]; 207 | } 208 | } 209 | 210 | out[0][i] = short_div(n, k, dividend, b); 211 | 212 | var mult_shift[100] = long_scalar_mult(n, k, out[0][i], b); 213 | var subtrahend[200]; 214 | for (var j = 0; j < m + k; j++) { 215 | subtrahend[j] = 0; 216 | } 217 | for (var j = 0; j <= k; j++) { 218 | if (i + j < m + k) { 219 | subtrahend[i + j] = mult_shift[j]; 220 | } 221 | } 222 | remainder = long_sub(n, m + k, remainder, subtrahend); 223 | } 224 | for (var i = 0; i < k; i++) { 225 | out[1][i] = remainder[i]; 226 | } 227 | out[1][k] = 0; 228 | 229 | return out; 230 | } 231 | 232 | // n bits per register 233 | // a has k + 1 registers 234 | // b has k registers 235 | // assumes leading digit of b is at least 2 ** (n - 1) 236 | // 0 <= a < (2**n) * b 237 | function short_div_norm(n, k, a, b) { 238 | var qhat = (a[k] * (1 << n) + a[k - 1]) \ b[k - 1]; 239 | if (qhat > (1 << n) - 1) { 240 | qhat = (1 << n) - 1; 241 | } 242 | 243 | var mult[100] = long_scalar_mult(n, k, qhat, b); 244 | if (long_gt(n, k + 1, mult, a) == 1) { 245 | mult = long_sub(n, k + 1, mult, b); 246 | if (long_gt(n, k + 1, mult, a) == 1) { 247 | return qhat - 2; 248 | } else { 249 | return qhat - 1; 250 | } 251 | } else { 252 | return qhat; 253 | } 254 | } 255 | 256 | // n bits per register 257 | // a has k + 1 registers 258 | // b has k registers 259 | // assumes leading digit of b is non-zero 260 | // 0 <= a < (2**n) * b 261 | function short_div(n, k, a, b) { 262 | var scale = (1 << n) \ (1 + b[k - 1]); 263 | 264 | // k + 2 registers now 265 | var norm_a[200] = long_scalar_mult(n, k + 1, scale, a); 266 | // k + 1 registers now 267 | var norm_b[200] = long_scalar_mult(n, k, scale, b); 268 | 269 | var ret; 270 | if (norm_b[k] != 0) { 271 | ret = short_div_norm(n, k + 1, norm_a, norm_b); 272 | } else { 273 | ret = short_div_norm(n, k, norm_a, norm_b); 274 | } 275 | return ret; 276 | } 277 | 278 | // n bits per register 279 | // a and b both have k registers 280 | // out[0] has length 2 * k 281 | // adapted from BigMulShortLong and LongToShortNoEndCarry2 witness computation 282 | function prod(n, k, a, b) { 283 | // first compute the intermediate values. taken from BigMulShortLong 284 | var prod_val[100]; // length is 2 * k - 1 285 | for (var i = 0; i < 2 * k - 1; i++) { 286 | prod_val[i] = 0; 287 | if (i < k) { 288 | for (var a_idx = 0; a_idx <= i; a_idx++) { 289 | prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; 290 | } 291 | } else { 292 | for (var a_idx = i - k + 1; a_idx < k; a_idx++) { 293 | prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; 294 | } 295 | } 296 | } 297 | 298 | // now do a bunch of carrying to make sure registers not overflowed. taken from LongToShortNoEndCarry2 299 | var out[100]; // length is 2 * k 300 | 301 | var split[100][3]; // first dimension has length 2 * k - 1 302 | for (var i = 0; i < 2 * k - 1; i++) { 303 | split[i] = SplitThreeFn(prod_val[i], n, n, n); 304 | } 305 | 306 | var carry[100]; // length is 2 * k - 1 307 | carry[0] = 0; 308 | out[0] = split[0][0]; 309 | if (2 * k - 1 > 1) { 310 | var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); 311 | out[1] = sumAndCarry[0]; 312 | carry[1] = sumAndCarry[1]; 313 | } 314 | if (2 * k - 1 > 2) { 315 | for (var i = 2; i < 2 * k - 1; i++) { 316 | var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); 317 | out[i] = sumAndCarry[0]; 318 | carry[i] = sumAndCarry[1]; 319 | } 320 | out[2 * k - 1] = split[2*k-2][1] + split[2*k-3][2] + carry[2*k-2]; 321 | } 322 | return out; 323 | } 324 | 325 | // n bits per register 326 | // a has k registers 327 | // p has k registers 328 | // e has k registers 329 | // k * n <= 500 330 | // p is a prime 331 | // computes a^e mod p 332 | function mod_exp(n, k, a, p, e) { 333 | var eBits[500]; // length is k * n 334 | for (var i = 0; i < k; i++) { 335 | for (var j = 0; j < n; j++) { 336 | eBits[j + n * i] = (e[i] >> j) & 1; 337 | } 338 | } 339 | 340 | var out[100]; // length is k 341 | for (var i = 0; i < 100; i++) { 342 | out[i] = 0; 343 | } 344 | out[0] = 1; 345 | 346 | // repeated squaring 347 | for (var i = k * n - 1; i >= 0; i--) { 348 | // multiply by a if bit is 0 349 | if (eBits[i] == 1) { 350 | var temp[200]; // length 2 * k 351 | temp = prod(n, k, out, a); 352 | var temp2[2][100]; 353 | temp2 = long_div(n, k, k, temp, p); 354 | out = temp2[1]; 355 | } 356 | 357 | // square, unless we're at the end 358 | if (i > 0) { 359 | var temp[200]; // length 2 * k 360 | temp = prod(n, k, out, out); 361 | var temp2[2][100]; 362 | temp2 = long_div(n, k, k, temp, p); 363 | out = temp2[1]; 364 | } 365 | 366 | } 367 | return out; 368 | } 369 | 370 | // n bits per register 371 | // a has k registers 372 | // p has k registers 373 | // k * n <= 500 374 | // p is a prime 375 | // if a == 0 mod p, returns 0 376 | // else computes inv = a^(p-2) mod p 377 | function mod_inv(n, k, a, p) { 378 | var isZero = 1; 379 | for (var i = 0; i < k; i++) { 380 | if (a[i] != 0) { 381 | isZero = 0; 382 | } 383 | } 384 | if (isZero == 1) { 385 | var ret[100]; 386 | for (var i = 0; i < k; i++) { 387 | ret[i] = 0; 388 | } 389 | return ret; 390 | } 391 | 392 | var pCopy[100]; 393 | for (var i = 0; i < 100; i++) { 394 | if (i < k) { 395 | pCopy[i] = p[i]; 396 | } else { 397 | pCopy[i] = 0; 398 | } 399 | } 400 | 401 | var two[100]; 402 | for (var i = 0; i < 100; i++) { 403 | two[i] = 0; 404 | } 405 | two[0] = 2; 406 | 407 | var pMinusTwo[100]; 408 | pMinusTwo = long_sub(n, k, pCopy, two); // length k 409 | var out[100]; 410 | out = mod_exp(n, k, a, pCopy, pMinusTwo); 411 | return out; 412 | } 413 | 414 | // a, b and out are all n bits k registers 415 | function long_sub_mod_p(n, k, a, b, p){ 416 | var gt = long_gt(n, k, a, b); 417 | var tmp[100]; 418 | if(gt){ 419 | tmp = long_sub(n, k, a, b); 420 | } 421 | else{ 422 | tmp = long_sub(n, k, b, a); 423 | } 424 | var out[2][100]; 425 | for(var i = k;i < 2 * k; i++){ 426 | tmp[i] = 0; 427 | } 428 | out = long_div(n, k, k, tmp, p); 429 | if(gt==0){ 430 | tmp = long_sub(n, k, p, out[1]); 431 | } 432 | return tmp; 433 | } 434 | 435 | // a, b, p and out are all n bits k registers 436 | function prod_mod_p(n, k, a, b, p){ 437 | var tmp[100]; 438 | var result[2][100]; 439 | tmp = prod(n, k, a, b); 440 | result = long_div(n, k, k, tmp, p); 441 | return result[1]; 442 | } 443 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/secp256k1.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "../../node_modules/circomlib/circuits/bitify.circom"; 4 | 5 | include "bigint.circom"; 6 | include "bigint_4x64_mult.circom"; 7 | include "bigint_func.circom"; 8 | include "secp256k1_func.circom"; 9 | include "secp256k1_utils.circom"; 10 | 11 | // Implements: 12 | // x_1 + x_2 + x_3 - lambda^2 = 0 mod p 13 | // where p is the secp256k1 field size 14 | // and lambda is the slope of the line between (x_1, y_1) and (x_2, y_2) 15 | // this equation is equivalent to: 16 | // x1^3 + x2^3 - x1^2x2 - x1x2^2 + x2^2x3 + x1^2x3 - 2x1x2x3 - y2^2 - 2y1y2 - y1^2 = 0 mod p 17 | template AddUnequalCubicConstraint() { 18 | signal input x1[4]; 19 | signal input y1[4]; 20 | signal input x2[4]; 21 | signal input y2[4]; 22 | signal input x3[4]; 23 | signal input y3[4]; 24 | 25 | signal x13[10]; // 197 bits 26 | component x13Comp = A3NoCarry(); 27 | for (var i = 0; i < 4; i++) x13Comp.a[i] <== x1[i]; 28 | for (var i = 0; i < 10; i++) x13[i] <== x13Comp.a3[i]; 29 | 30 | signal x23[10]; // 197 bits 31 | component x23Comp = A3NoCarry(); 32 | for (var i = 0; i < 4; i++) x23Comp.a[i] <== x2[i]; 33 | for (var i = 0; i < 10; i++) x23[i] <== x23Comp.a3[i]; 34 | 35 | signal x12x2[10]; // 197 bits 36 | component x12x2Comp = A2B1NoCarry(); 37 | for (var i = 0; i < 4; i++) x12x2Comp.a[i] <== x1[i]; 38 | for (var i = 0; i < 4; i++) x12x2Comp.b[i] <== x2[i]; 39 | for (var i = 0; i < 10; i++) x12x2[i] <== x12x2Comp.a2b1[i]; 40 | 41 | signal x1x22[10]; // 197 bits 42 | component x1x22Comp = A2B1NoCarry(); 43 | for (var i = 0; i < 4; i++) x1x22Comp.a[i] <== x2[i]; 44 | for (var i = 0; i < 4; i++) x1x22Comp.b[i] <== x1[i]; 45 | for (var i = 0; i < 10; i++) x1x22[i] <== x1x22Comp.a2b1[i]; 46 | 47 | signal x22x3[10]; // 197 bits 48 | component x22x3Comp = A2B1NoCarry(); 49 | for (var i = 0; i < 4; i++) x22x3Comp.a[i] <== x2[i]; 50 | for (var i = 0; i < 4; i++) x22x3Comp.b[i] <== x3[i]; 51 | for (var i = 0; i < 10; i++) x22x3[i] <== x22x3Comp.a2b1[i]; 52 | 53 | signal x12x3[10]; // 197 bits 54 | component x12x3Comp = A2B1NoCarry(); 55 | for (var i = 0; i < 4; i++) x12x3Comp.a[i] <== x1[i]; 56 | for (var i = 0; i < 4; i++) x12x3Comp.b[i] <== x3[i]; 57 | for (var i = 0; i < 10; i++) x12x3[i] <== x12x3Comp.a2b1[i]; 58 | 59 | signal x1x2x3[10]; // 197 bits 60 | component x1x2x3Comp = A1B1C1NoCarry(); 61 | for (var i = 0; i < 4; i++) x1x2x3Comp.a[i] <== x1[i]; 62 | for (var i = 0; i < 4; i++) x1x2x3Comp.b[i] <== x2[i]; 63 | for (var i = 0; i < 4; i++) x1x2x3Comp.c[i] <== x3[i]; 64 | for (var i = 0; i < 10; i++) x1x2x3[i] <== x1x2x3Comp.a1b1c1[i]; 65 | 66 | signal y12[7]; // 130 bits 67 | component y12Comp = A2NoCarry(); 68 | for (var i = 0; i < 4; i++) y12Comp.a[i] <== y1[i]; 69 | for (var i = 0; i < 7; i++) y12[i] <== y12Comp.a2[i]; 70 | 71 | signal y22[7]; // 130 bits 72 | component y22Comp = A2NoCarry(); 73 | for (var i = 0; i < 4; i++) y22Comp.a[i] <== y2[i]; 74 | for (var i = 0; i < 7; i++) y22[i] <== y22Comp.a2[i]; 75 | 76 | signal y1y2[7]; // 130 bits 77 | component y1y2Comp = BigMultNoCarry(64, 64, 64, 4, 4); 78 | for (var i = 0; i < 4; i++) y1y2Comp.a[i] <== y1[i]; 79 | for (var i = 0; i < 4; i++) y1y2Comp.b[i] <== y2[i]; 80 | for (var i = 0; i < 7; i++) y1y2[i] <== y1y2Comp.out[i]; 81 | 82 | component zeroCheck = CheckCubicModPIsZero(200); // 200 bits per register 83 | for (var i = 0; i < 10; i++) { 84 | if (i < 7) { 85 | zeroCheck.in[i] <== x13[i] + x23[i] - x12x2[i] - x1x22[i] + x22x3[i] + x12x3[i] - 2 * x1x2x3[i] - y12[i] + 2 * y1y2[i] - y22[i]; 86 | } else { 87 | zeroCheck.in[i] <== x13[i] + x23[i] - x12x2[i] - x1x22[i] + x22x3[i] + x12x3[i] - 2 * x1x2x3[i]; 88 | } 89 | } 90 | } 91 | 92 | // Implements: 93 | // x3y2 + x2y3 + x2y1 - x3y1 - x1y2 - x1y3 == 0 mod p 94 | // for secp prime p 95 | // used to show (x1, y1), (x2, y2), (x3, -y3) are co-linear 96 | template Secp256k1PointOnLine() { 97 | signal input x1[4]; 98 | signal input y1[4]; 99 | 100 | signal input x2[4]; 101 | signal input y2[4]; 102 | 103 | signal input x3[4]; 104 | signal input y3[4]; 105 | 106 | // first, we compute representations of x3y2, x2y3, x2y1, x3y1, x1y2, x1y3. 107 | // these representations have overflowed, nonnegative registers 108 | signal x3y2[7]; 109 | component x3y2Comp = BigMultNoCarry(64, 64, 64, 4, 4); 110 | for (var i = 0; i < 4; i++) x3y2Comp.a[i] <== x3[i]; 111 | for (var i = 0; i < 4; i++) x3y2Comp.b[i] <== y2[i]; 112 | for (var i = 0; i < 7; i++) x3y2[i] <== x3y2Comp.out[i]; // 130 bits 113 | 114 | signal x3y1[7]; 115 | component x3y1Comp = BigMultNoCarry(64, 64, 64, 4, 4); 116 | for (var i = 0; i < 4; i++) x3y1Comp.a[i] <== x3[i]; 117 | for (var i = 0; i < 4; i++) x3y1Comp.b[i] <== y1[i]; 118 | for (var i = 0; i < 7; i++) x3y1[i] <== x3y1Comp.out[i]; // 130 bits 119 | 120 | signal x2y3[7]; 121 | component x2y3Comp = BigMultNoCarry(64, 64, 64, 4, 4); 122 | for (var i = 0; i < 4; i++) x2y3Comp.a[i] <== x2[i]; 123 | for (var i = 0; i < 4; i++) x2y3Comp.b[i] <== y3[i]; 124 | for (var i = 0; i < 7; i++) x2y3[i] <== x2y3Comp.out[i]; // 130 bits 125 | 126 | signal x2y1[7]; 127 | component x2y1Comp = BigMultNoCarry(64, 64, 64, 4, 4); 128 | for (var i = 0; i < 4; i++) x2y1Comp.a[i] <== x2[i]; 129 | for (var i = 0; i < 4; i++) x2y1Comp.b[i] <== y1[i]; 130 | for (var i = 0; i < 7; i++) x2y1[i] <== x2y1Comp.out[i]; // 130 bits 131 | 132 | signal x1y3[7]; 133 | component x1y3Comp = BigMultNoCarry(64, 64, 64, 4, 4); 134 | for (var i = 0; i < 4; i++) x1y3Comp.a[i] <== x1[i]; 135 | for (var i = 0; i < 4; i++) x1y3Comp.b[i] <== y3[i]; 136 | for (var i = 0; i < 7; i++) x1y3[i] <== x1y3Comp.out[i]; // 130 bits 137 | 138 | signal x1y2[7]; 139 | component x1y2Comp = BigMultNoCarry(64, 64, 64, 4, 4); 140 | for (var i = 0; i < 4; i++) x1y2Comp.a[i] <== x1[i]; 141 | for (var i = 0; i < 4; i++) x1y2Comp.b[i] <== y2[i]; 142 | for (var i = 0; i < 7; i++) x1y2[i] <== x1y2Comp.out[i]; // 130 bits 143 | 144 | component zeroCheck = CheckQuadraticModPIsZero(132); 145 | for (var i = 0; i < 7; i++) { 146 | zeroCheck.in[i] <== x3y2[i] + x2y3[i] + x2y1[i] - x3y1[i] - x1y2[i] - x1y3[i]; 147 | } 148 | } 149 | 150 | template Secp256k1PointOnTangent() { 151 | signal input x1[4]; 152 | signal input y1[4]; 153 | signal input x3[4]; 154 | signal input y3[4]; 155 | 156 | // first, we compute representations of y1^2, y1y3, x1^3, x1^2x3 157 | signal y12[7]; // 130 bits 158 | component y12Comp = A2NoCarry(); 159 | for (var i = 0; i < 4; i++) y12Comp.a[i] <== y1[i]; 160 | for (var i = 0; i < 7; i++) y12[i] <== y12Comp.a2[i]; 161 | 162 | signal y1y3[7]; // 130 bits 163 | component y1y3Comp = BigMultNoCarry(64, 64, 64, 4, 4); 164 | for (var i = 0; i < 4; i++) y1y3Comp.a[i] <== y1[i]; 165 | for (var i = 0; i < 4; i++) y1y3Comp.b[i] <== y3[i]; 166 | for (var i = 0; i < 7; i++) y1y3[i] <== y1y3Comp.out[i]; 167 | 168 | signal x13[10]; // 197 bits 169 | component x13Comp = A3NoCarry(); 170 | for (var i = 0; i < 4; i++) x13Comp.a[i] <== x1[i]; 171 | for (var i = 0; i < 10; i++) x13[i] <== x13Comp.a3[i]; 172 | 173 | signal x12x3[10]; // 197 bits 174 | component x12x3Comp = A2B1NoCarry(); 175 | for (var i = 0; i < 4; i++) x12x3Comp.a[i] <== x1[i]; 176 | for (var i = 0; i < 4; i++) x12x3Comp.b[i] <== x3[i]; 177 | for (var i = 0; i < 10; i++) x12x3[i] <== x12x3Comp.a2b1[i]; 178 | 179 | component zeroCheck = CheckCubicModPIsZero(199); 180 | for (var i = 0; i < 10; i++) { 181 | if (i < 7) zeroCheck.in[i] <== 2 * y12[i] + 2 * y1y3[i] - 3 * x13[i] + 3 * x12x3[i]; 182 | else zeroCheck.in[i] <== -3 * x13[i] + 3 * x12x3[i]; 183 | } 184 | } 185 | 186 | // Implements: 187 | // x^3 + 7 - y^2 == 0 mod p 188 | // where p is the secp256k1 field size 189 | template Secp256k1PointOnCurve() { 190 | signal input x[4]; 191 | signal input y[4]; 192 | 193 | // first, we compute representations of x^3 and y^2. 194 | // these representations have overflowed, nonnegative registers 195 | signal x3[10]; // 197 bits 196 | component x3Comp = A3NoCarry(); 197 | for (var i = 0; i < 4; i++) x3Comp.a[i] <== x[i]; 198 | for (var i = 0; i < 10; i++) x3[i] <== x3Comp.a3[i]; 199 | 200 | signal y2[7]; // 130 bits 201 | component y2Comp = A2NoCarry(); 202 | for (var i = 0; i < 4; i++) y2Comp.a[i] <== y[i]; 203 | for (var i = 0; i < 7; i++) y2[i] <== y2Comp.a2[i]; 204 | 205 | component zeroCheck = CheckCubicModPIsZero(197); // 197 bits per register 206 | for (var i = 0; i < 10; i++) { 207 | if (i == 0) zeroCheck.in[i] <== x3[i] - y2[i] + 7; 208 | else if (i < 7) zeroCheck.in[i] <== x3[i] - y2[i]; 209 | else zeroCheck.in[i] <== x3[i]; 210 | } 211 | } 212 | 213 | template Secp256k1AddUnequal(n, k) { 214 | assert(n == 64 && k == 4); 215 | 216 | signal input a[2][k]; 217 | signal input b[2][k]; 218 | 219 | signal output out[2][k]; 220 | var x1[4]; 221 | var y1[4]; 222 | var x2[4]; 223 | var y2[4]; 224 | for(var i=0;i<4;i++){ 225 | x1[i] = a[0][i]; 226 | y1[i] = a[1][i]; 227 | x2[i] = b[0][i]; 228 | y2[i] = b[1][i]; 229 | } 230 | 231 | var tmp[2][100] = secp256k1_addunequal_func(n, k, x1, y1, x2, y2); 232 | for(var i = 0; i < k;i++){ 233 | out[0][i] <-- tmp[0][i]; 234 | out[1][i] <-- tmp[1][i]; 235 | } 236 | 237 | component cubic_constraint = AddUnequalCubicConstraint(); 238 | for(var i = 0; i < k; i++){ 239 | cubic_constraint.x1[i] <== x1[i]; 240 | cubic_constraint.y1[i] <== y1[i]; 241 | cubic_constraint.x2[i] <== x2[i]; 242 | cubic_constraint.y2[i] <== y2[i]; 243 | cubic_constraint.x3[i] <== out[0][i]; 244 | cubic_constraint.y3[i] <== out[1][i]; 245 | } 246 | 247 | component point_on_line = Secp256k1PointOnLine(); 248 | for(var i = 0; i < k; i++){ 249 | point_on_line.x1[i] <== a[0][i]; 250 | point_on_line.y1[i] <== a[1][i]; 251 | point_on_line.x2[i] <== b[0][i]; 252 | point_on_line.y2[i] <== b[1][i]; 253 | point_on_line.x3[i] <== out[0][i]; 254 | point_on_line.y3[i] <== out[1][i]; 255 | } 256 | 257 | component x_check_in_range = CheckInRangeSecp256k1(); 258 | component y_check_in_range = CheckInRangeSecp256k1(); 259 | for(var i = 0; i < k; i++){ 260 | x_check_in_range.in[i] <== out[0][i]; 261 | y_check_in_range.in[i] <== out[1][i]; 262 | } 263 | } 264 | 265 | template Secp256k1Double(n, k) { 266 | assert(n == 64 && k == 4); 267 | 268 | signal input in[2][k]; 269 | 270 | signal output out[2][k]; 271 | var x1[4]; 272 | var y1[4]; 273 | for(var i=0;i<4;i++){ 274 | x1[i] = in[0][i]; 275 | y1[i] = in[1][i]; 276 | } 277 | 278 | var tmp[2][100] = secp256k1_double_func(n, k, x1, y1); 279 | for(var i = 0; i < k;i++){ 280 | out[0][i] <-- tmp[0][i]; 281 | out[1][i] <-- tmp[1][i]; 282 | } 283 | 284 | component point_on_tangent = Secp256k1PointOnTangent(); 285 | for(var i = 0; i < k; i++){ 286 | point_on_tangent.x1[i] <== x1[i]; 287 | point_on_tangent.y1[i] <== y1[i]; 288 | point_on_tangent.x3[i] <== out[0][i]; 289 | point_on_tangent.y3[i] <== out[1][i]; 290 | } 291 | 292 | component point_on_curve = Secp256k1PointOnCurve(); 293 | for(var i = 0; i < k; i++){ 294 | point_on_curve.x[i] <== out[0][i]; 295 | point_on_curve.y[i] <== out[1][i]; 296 | } 297 | 298 | component x_check_in_range = CheckInRangeSecp256k1(); 299 | component y_check_in_range = CheckInRangeSecp256k1(); 300 | for(var i = 0; i < k; i++){ 301 | x_check_in_range.in[i] <== out[0][i]; 302 | y_check_in_range.in[i] <== out[1][i]; 303 | } 304 | 305 | component x3_eq_x1 = BigIsEqual(4); 306 | for(var i = 0; i < k; i++){ 307 | x3_eq_x1.in[0][i] <== out[0][i]; 308 | x3_eq_x1.in[1][i] <== x1[i]; 309 | } 310 | x3_eq_x1.out === 0; 311 | } 312 | 313 | template Secp256k1ScalarMult(n, k) { 314 | signal input scalar[k]; 315 | signal input point[2][k]; 316 | 317 | signal output out[2][k]; 318 | 319 | component n2b[k]; 320 | for (var i = 0; i < k; i++) { 321 | n2b[i] = Num2Bits(n); 322 | n2b[i].in <== scalar[i]; 323 | } 324 | 325 | // has_prev_non_zero[n * i + j] == 1 if there is a nonzero bit in location [i][j] or higher order bit 326 | component has_prev_non_zero[k * n]; 327 | for (var i = k - 1; i >= 0; i--) { 328 | for (var j = n - 1; j >= 0; j--) { 329 | has_prev_non_zero[n * i + j] = OR(); 330 | if (i == k - 1 && j == n - 1) { 331 | has_prev_non_zero[n * i + j].a <== 0; 332 | has_prev_non_zero[n * i + j].b <== n2b[i].out[j]; 333 | } else { 334 | has_prev_non_zero[n * i + j].a <== has_prev_non_zero[n * i + j + 1].out; 335 | has_prev_non_zero[n * i + j].b <== n2b[i].out[j]; 336 | } 337 | } 338 | } 339 | 340 | signal partial[n * k][2][k]; 341 | signal intermed[n * k - 1][2][k]; 342 | component adders[n * k - 1]; 343 | component doublers[n * k - 1]; 344 | for (var i = k - 1; i >= 0; i--) { 345 | for (var j = n - 1; j >= 0; j--) { 346 | if (i == k - 1 && j == n - 1) { 347 | for (var idx = 0; idx < k; idx++) { 348 | partial[n * i + j][0][idx] <== point[0][idx]; 349 | partial[n * i + j][1][idx] <== point[1][idx]; 350 | } 351 | } 352 | if (i < k - 1 || j < n - 1) { 353 | adders[n * i + j] = Secp256k1AddUnequal(n, k); 354 | doublers[n * i + j] = Secp256k1Double(n, k); 355 | for (var idx = 0; idx < k; idx++) { 356 | doublers[n * i + j].in[0][idx] <== partial[n * i + j + 1][0][idx]; 357 | doublers[n * i + j].in[1][idx] <== partial[n * i + j + 1][1][idx]; 358 | } 359 | for (var idx = 0; idx < k; idx++) { 360 | adders[n * i + j].a[0][idx] <== doublers[n * i + j].out[0][idx]; 361 | adders[n * i + j].a[1][idx] <== doublers[n * i + j].out[1][idx]; 362 | adders[n * i + j].b[0][idx] <== point[0][idx]; 363 | adders[n * i + j].b[1][idx] <== point[1][idx]; 364 | } 365 | // partial[n * i + j] 366 | // = has_prev_non_zero[n * i + j + 1] * ((1 - n2b[i].out[j]) * doublers[n * i + j] + n2b[i].out[j] * adders[n * i + j]) 367 | // + (1 - has_prev_non_zero[n * i + j + 1]) * point 368 | for (var idx = 0; idx < k; idx++) { 369 | intermed[n * i + j][0][idx] <== n2b[i].out[j] * (adders[n * i + j].out[0][idx] - doublers[n * i + j].out[0][idx]) + doublers[n * i + j].out[0][idx]; 370 | intermed[n * i + j][1][idx] <== n2b[i].out[j] * (adders[n * i + j].out[1][idx] - doublers[n * i + j].out[1][idx]) + doublers[n * i + j].out[1][idx]; 371 | partial[n * i + j][0][idx] <== has_prev_non_zero[n * i + j + 1].out * (intermed[n * i + j][0][idx] - point[0][idx]) + point[0][idx]; 372 | partial[n * i + j][1][idx] <== has_prev_non_zero[n * i + j + 1].out * (intermed[n * i + j][1][idx] - point[1][idx]) + point[1][idx]; 373 | } 374 | } 375 | } 376 | } 377 | 378 | for (var idx = 0; idx < k; idx++) { 379 | out[0][idx] <== partial[0][0][idx]; 380 | out[1][idx] <== partial[0][1][idx]; 381 | } 382 | } 383 | -------------------------------------------------------------------------------- /circuits/circom-ecdsa-circuits/bigint.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.2; 2 | 3 | include "../../node_modules/circomlib/circuits/comparators.circom"; 4 | include "../../node_modules/circomlib/circuits/bitify.circom"; 5 | include "../../node_modules/circomlib/circuits/gates.circom"; 6 | 7 | include "bigint_func.circom"; 8 | 9 | // addition mod 2**n with carry bit 10 | template ModSum(n) { 11 | assert(n <= 252); 12 | signal input a; 13 | signal input b; 14 | signal output sum; 15 | signal output carry; 16 | 17 | component n2b = Num2Bits(n + 1); 18 | n2b.in <== a + b; 19 | carry <== n2b.out[n]; 20 | sum <== a + b - carry * (1 << n); 21 | } 22 | 23 | // a - b 24 | template ModSub(n) { 25 | assert(n <= 252); 26 | signal input a; 27 | signal input b; 28 | signal output out; 29 | signal output borrow; 30 | component lt = LessThan(n); 31 | lt.in[0] <== a; 32 | lt.in[1] <== b; 33 | borrow <== lt.out; 34 | out <== borrow * (1 << n) + a - b; 35 | } 36 | 37 | // a - b - c 38 | // assume a - b - c + 2**n >= 0 39 | template ModSubThree(n) { 40 | assert(n + 2 <= 253); 41 | signal input a; 42 | signal input b; 43 | signal input c; 44 | assert(a - b - c + (1 << n) >= 0); 45 | signal output out; 46 | signal output borrow; 47 | signal b_plus_c; 48 | b_plus_c <== b + c; 49 | component lt = LessThan(n + 1); 50 | lt.in[0] <== a; 51 | lt.in[1] <== b_plus_c; 52 | borrow <== lt.out; 53 | out <== borrow * (1 << n) + a - b_plus_c; 54 | } 55 | 56 | template ModSumThree(n) { 57 | assert(n + 2 <= 253); 58 | signal input a; 59 | signal input b; 60 | signal input c; 61 | signal output sum; 62 | signal output carry; 63 | 64 | component n2b = Num2Bits(n + 2); 65 | n2b.in <== a + b + c; 66 | carry <== n2b.out[n] + 2 * n2b.out[n + 1]; 67 | sum <== a + b + c - carry * (1 << n); 68 | } 69 | 70 | template ModSumFour(n) { 71 | assert(n + 2 <= 253); 72 | signal input a; 73 | signal input b; 74 | signal input c; 75 | signal input d; 76 | signal output sum; 77 | signal output carry; 78 | 79 | component n2b = Num2Bits(n + 2); 80 | n2b.in <== a + b + c + d; 81 | carry <== n2b.out[n] + 2 * n2b.out[n + 1]; 82 | sum <== a + b + c + d - carry * (1 << n); 83 | } 84 | 85 | // product mod 2**n with carry 86 | template ModProd(n) { 87 | assert(n <= 126); 88 | signal input a; 89 | signal input b; 90 | signal output prod; 91 | signal output carry; 92 | 93 | component n2b = Num2Bits(2 * n); 94 | n2b.in <== a * b; 95 | 96 | component b2n1 = Bits2Num(n); 97 | component b2n2 = Bits2Num(n); 98 | var i; 99 | for (i = 0; i < n; i++) { 100 | b2n1.in[i] <== n2b.out[i]; 101 | b2n2.in[i] <== n2b.out[i + n]; 102 | } 103 | prod <== b2n1.out; 104 | carry <== b2n2.out; 105 | } 106 | 107 | // split a n + m bit input into two outputs 108 | template Split(n, m) { 109 | assert(n <= 126); 110 | signal input in; 111 | signal output small; 112 | signal output big; 113 | 114 | small <-- in % (1 << n); 115 | big <-- in \ (1 << n); 116 | 117 | component n2b_small = Num2Bits(n); 118 | n2b_small.in <== small; 119 | component n2b_big = Num2Bits(m); 120 | n2b_big.in <== big; 121 | 122 | in === small + big * (1 << n); 123 | } 124 | 125 | // split a n + m + k bit input into three outputs 126 | template SplitThree(n, m, k) { 127 | assert(n <= 126); 128 | signal input in; 129 | signal output small; 130 | signal output medium; 131 | signal output big; 132 | 133 | small <-- in % (1 << n); 134 | medium <-- (in \ (1 << n)) % (1 << m); 135 | big <-- in \ (1 << n + m); 136 | 137 | component n2b_small = Num2Bits(n); 138 | n2b_small.in <== small; 139 | component n2b_medium = Num2Bits(m); 140 | n2b_medium.in <== medium; 141 | component n2b_big = Num2Bits(k); 142 | n2b_big.in <== big; 143 | 144 | in === small + medium * (1 << n) + big * (1 << n + m); 145 | } 146 | 147 | // a[i], b[i] in 0... 2**n-1 148 | // represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) 149 | template BigAdd(n, k) { 150 | assert(n <= 252); 151 | signal input a[k]; 152 | signal input b[k]; 153 | signal output out[k + 1]; 154 | 155 | component unit0 = ModSum(n); 156 | unit0.a <== a[0]; 157 | unit0.b <== b[0]; 158 | out[0] <== unit0.sum; 159 | 160 | component unit[k - 1]; 161 | for (var i = 1; i < k; i++) { 162 | unit[i - 1] = ModSumThree(n); 163 | unit[i - 1].a <== a[i]; 164 | unit[i - 1].b <== b[i]; 165 | if (i == 1) { 166 | unit[i - 1].c <== unit0.carry; 167 | } else { 168 | unit[i - 1].c <== unit[i - 2].carry; 169 | } 170 | out[i] <== unit[i - 1].sum; 171 | } 172 | out[k] <== unit[k - 2].carry; 173 | } 174 | 175 | // a and b have n-bit registers 176 | // a has ka registers, each with NONNEGATIVE ma-bit values (ma can be > n) 177 | // b has kb registers, each with NONNEGATIVE mb-bit values (mb can be > n) 178 | // out has ka + kb - 1 registers, each with (ma + mb + ceil(log(max(ka, kb))))-bit values 179 | template BigMultNoCarry(n, ma, mb, ka, kb) { 180 | assert(ma + mb <= 253); 181 | signal input a[ka]; 182 | signal input b[kb]; 183 | signal output out[ka + kb - 1]; 184 | 185 | var prod_val[ka + kb - 1]; 186 | for (var i = 0; i < ka + kb - 1; i++) { 187 | prod_val[i] = 0; 188 | } 189 | for (var i = 0; i < ka; i++) { 190 | for (var j = 0; j < kb; j++) { 191 | prod_val[i + j] += a[i] * b[j]; 192 | } 193 | } 194 | for (var i = 0; i < ka + kb - 1; i++) { 195 | out[i] <-- prod_val[i]; 196 | } 197 | 198 | var a_poly[ka + kb - 1]; 199 | var b_poly[ka + kb - 1]; 200 | var out_poly[ka + kb - 1]; 201 | for (var i = 0; i < ka + kb - 1; i++) { 202 | out_poly[i] = 0; 203 | a_poly[i] = 0; 204 | b_poly[i] = 0; 205 | for (var j = 0; j < ka + kb - 1; j++) { 206 | out_poly[i] = out_poly[i] + out[j] * (i ** j); 207 | } 208 | for (var j = 0; j < ka; j++) { 209 | a_poly[i] = a_poly[i] + a[j] * (i ** j); 210 | } 211 | for (var j = 0; j < kb; j++) { 212 | b_poly[i] = b_poly[i] + b[j] * (i ** j); 213 | } 214 | } 215 | for (var i = 0; i < ka + kb - 1; i++) { 216 | out_poly[i] === a_poly[i] * b_poly[i]; 217 | } 218 | } 219 | 220 | 221 | // in[i] contains longs 222 | // out[i] contains shorts 223 | template LongToShortNoEndCarry(n, k) { 224 | assert(n <= 126); 225 | signal input in[k]; 226 | signal output out[k+1]; 227 | 228 | var split[k][3]; 229 | for (var i = 0; i < k; i++) { 230 | split[i] = SplitThreeFn(in[i], n, n, n); 231 | } 232 | 233 | var carry[k]; 234 | carry[0] = 0; 235 | out[0] <-- split[0][0]; 236 | if (k == 1) { 237 | out[1] <-- split[0][1]; 238 | } 239 | if (k > 1) { 240 | var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); 241 | out[1] <-- sumAndCarry[0]; 242 | carry[1] = sumAndCarry[1]; 243 | } 244 | if (k == 2) { 245 | out[2] <-- split[1][1] + split[0][2] + carry[1]; 246 | } 247 | if (k > 2) { 248 | for (var i = 2; i < k; i++) { 249 | var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); 250 | out[i] <-- sumAndCarry[0]; 251 | carry[i] = sumAndCarry[1]; 252 | } 253 | out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; 254 | } 255 | 256 | component outRangeChecks[k+1]; 257 | for (var i = 0; i < k+1; i++) { 258 | outRangeChecks[i] = Num2Bits(n); 259 | outRangeChecks[i].in <== out[i]; 260 | } 261 | 262 | signal runningCarry[k]; 263 | component runningCarryRangeChecks[k]; 264 | runningCarry[0] <-- (in[0] - out[0]) / (1 << n); 265 | runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); 266 | runningCarryRangeChecks[0].in <== runningCarry[0]; 267 | runningCarry[0] * (1 << n) === in[0] - out[0]; 268 | for (var i = 1; i < k; i++) { 269 | runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); 270 | runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); 271 | runningCarryRangeChecks[i].in <== runningCarry[i]; 272 | runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; 273 | } 274 | runningCarry[k-1] === out[k]; 275 | } 276 | 277 | template BigMult(n, k) { 278 | signal input a[k]; 279 | signal input b[k]; 280 | signal output out[2 * k]; 281 | 282 | component mult = BigMultNoCarry(n, n, n, k, k); 283 | for (var i = 0; i < k; i++) { 284 | mult.a[i] <== a[i]; 285 | mult.b[i] <== b[i]; 286 | } 287 | 288 | // no carry is possible in the highest order register 289 | component longshort = LongToShortNoEndCarry(n, 2 * k - 1); 290 | for (var i = 0; i < 2 * k - 1; i++) { 291 | longshort.in[i] <== mult.out[i]; 292 | } 293 | for (var i = 0; i < 2 * k; i++) { 294 | out[i] <== longshort.out[i]; 295 | } 296 | } 297 | 298 | template BigLessThan(n, k){ 299 | signal input a[k]; 300 | signal input b[k]; 301 | signal output out; 302 | 303 | component lt[k]; 304 | component eq[k]; 305 | for (var i = 0; i < k; i++) { 306 | lt[i] = LessThan(n); 307 | lt[i].in[0] <== a[i]; 308 | lt[i].in[1] <== b[i]; 309 | eq[i] = IsEqual(); 310 | eq[i].in[0] <== a[i]; 311 | eq[i].in[1] <== b[i]; 312 | } 313 | 314 | // ors[i] holds (lt[k - 1] || (eq[k - 1] && lt[k - 2]) .. || (eq[k - 1] && .. && lt[i])) 315 | // ands[i] holds (eq[k - 1] && .. && lt[i]) 316 | // eq_ands[i] holds (eq[k - 1] && .. && eq[i]) 317 | component ors[k - 1]; 318 | component ands[k - 1]; 319 | component eq_ands[k - 1]; 320 | for (var i = k - 2; i >= 0; i--) { 321 | ands[i] = AND(); 322 | eq_ands[i] = AND(); 323 | ors[i] = OR(); 324 | 325 | if (i == k - 2) { 326 | ands[i].a <== eq[k - 1].out; 327 | ands[i].b <== lt[k - 2].out; 328 | eq_ands[i].a <== eq[k - 1].out; 329 | eq_ands[i].b <== eq[k - 2].out; 330 | ors[i].a <== lt[k - 1].out; 331 | ors[i].b <== ands[i].out; 332 | } else { 333 | ands[i].a <== eq_ands[i + 1].out; 334 | ands[i].b <== lt[i].out; 335 | eq_ands[i].a <== eq_ands[i + 1].out; 336 | eq_ands[i].b <== eq[i].out; 337 | ors[i].a <== ors[i + 1].out; 338 | ors[i].b <== ands[i].out; 339 | } 340 | } 341 | out <== ors[0].out; 342 | } 343 | 344 | template BigIsEqual(k){ 345 | signal input in[2][k]; 346 | signal output out; 347 | component isEqual[k+1]; 348 | var sum = 0; 349 | for(var i = 0; i < k; i++){ 350 | isEqual[i] = IsEqual(); 351 | isEqual[i].in[0] <== in[0][i]; 352 | isEqual[i].in[1] <== in[1][i]; 353 | sum = sum + isEqual[i].out; 354 | } 355 | 356 | isEqual[k] = IsEqual(); 357 | isEqual[k].in[0] <== sum; 358 | isEqual[k].in[1] <== k; 359 | out <== isEqual[k].out; 360 | } 361 | 362 | // leading register of b should be non-zero 363 | template BigMod(n, k) { 364 | assert(n <= 126); 365 | signal input a[2 * k]; 366 | signal input b[k]; 367 | 368 | signal output div[k + 1]; 369 | signal output mod[k]; 370 | 371 | var longdiv[2][100] = long_div(n, k, k, a, b); 372 | for (var i = 0; i < k; i++) { 373 | div[i] <-- longdiv[0][i]; 374 | mod[i] <-- longdiv[1][i]; 375 | } 376 | div[k] <-- longdiv[0][k]; 377 | component div_range_checks[k + 1]; 378 | for (var i = 0; i <= k; i++) { 379 | div_range_checks[i] = Num2Bits(n); 380 | div_range_checks[i].in <== div[i]; 381 | } 382 | component mod_range_checks[k]; 383 | for (var i = 0; i < k; i++) { 384 | mod_range_checks[i] = Num2Bits(n); 385 | mod_range_checks[i].in <== mod[i]; 386 | } 387 | 388 | component mul = BigMult(n, k + 1); 389 | for (var i = 0; i < k; i++) { 390 | mul.a[i] <== div[i]; 391 | mul.b[i] <== b[i]; 392 | } 393 | mul.a[k] <== div[k]; 394 | mul.b[k] <== 0; 395 | 396 | component add = BigAdd(n, 2 * k + 2); 397 | for (var i = 0; i < 2 * k; i++) { 398 | add.a[i] <== mul.out[i]; 399 | if (i < k) { 400 | add.b[i] <== mod[i]; 401 | } else { 402 | add.b[i] <== 0; 403 | } 404 | } 405 | add.a[2 * k] <== mul.out[2 * k]; 406 | add.a[2 * k + 1] <== mul.out[2 * k + 1]; 407 | add.b[2 * k] <== 0; 408 | add.b[2 * k + 1] <== 0; 409 | 410 | for (var i = 0; i < 2 * k; i++) { 411 | add.out[i] === a[i]; 412 | } 413 | add.out[2 * k] === 0; 414 | add.out[2 * k + 1] === 0; 415 | 416 | component lt = BigLessThan(n, k); 417 | for (var i = 0; i < k; i++) { 418 | lt.a[i] <== mod[i]; 419 | lt.b[i] <== b[i]; 420 | } 421 | lt.out === 1; 422 | } 423 | 424 | // a[i], b[i] in 0... 2**n-1 425 | // represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) 426 | // assume a >= b 427 | template BigSub(n, k) { 428 | assert(n <= 252); 429 | signal input a[k]; 430 | signal input b[k]; 431 | signal output out[k]; 432 | signal output underflow; 433 | 434 | component unit0 = ModSub(n); 435 | unit0.a <== a[0]; 436 | unit0.b <== b[0]; 437 | out[0] <== unit0.out; 438 | 439 | component unit[k - 1]; 440 | for (var i = 1; i < k; i++) { 441 | unit[i - 1] = ModSubThree(n); 442 | unit[i - 1].a <== a[i]; 443 | unit[i - 1].b <== b[i]; 444 | if (i == 1) { 445 | unit[i - 1].c <== unit0.borrow; 446 | } else { 447 | unit[i - 1].c <== unit[i - 2].borrow; 448 | } 449 | out[i] <== unit[i - 1].out; 450 | } 451 | underflow <== unit[k - 2].borrow; 452 | } 453 | 454 | // calculates (a - b) % p, where a, b < p 455 | // note: does not assume a >= b 456 | template BigSubModP(n, k){ 457 | assert(n <= 252); 458 | signal input a[k]; 459 | signal input b[k]; 460 | signal input p[k]; 461 | signal output out[k]; 462 | component sub = BigSub(n, k); 463 | for (var i = 0; i < k; i++){ 464 | sub.a[i] <== a[i]; 465 | sub.b[i] <== b[i]; 466 | } 467 | signal flag; 468 | flag <== sub.underflow; 469 | component add = BigAdd(n, k); 470 | for (var i = 0; i < k; i++){ 471 | add.a[i] <== sub.out[i]; 472 | add.b[i] <== p[i]; 473 | } 474 | signal tmp[k]; 475 | for (var i = 0; i < k; i++){ 476 | tmp[i] <== (1 - flag) * sub.out[i]; 477 | out[i] <== tmp[i] + flag * add.out[i]; 478 | } 479 | } 480 | 481 | template BigMultModP(n, k) { 482 | assert(n <= 252); 483 | signal input a[k]; 484 | signal input b[k]; 485 | signal input p[k]; 486 | signal output out[k]; 487 | 488 | component big_mult = BigMult(n, k); 489 | for (var i = 0; i < k; i++) { 490 | big_mult.a[i] <== a[i]; 491 | big_mult.b[i] <== b[i]; 492 | } 493 | component big_mod = BigMod(n, k); 494 | for (var i = 0; i < 2 * k; i++) { 495 | big_mod.a[i] <== big_mult.out[i]; 496 | } 497 | for (var i = 0; i < k; i++) { 498 | big_mod.b[i] <== p[i]; 499 | } 500 | for (var i = 0; i < k; i++) { 501 | out[i] <== big_mod.mod[i]; 502 | } 503 | } 504 | 505 | template BigModInv(n, k) { 506 | assert(n <= 252); 507 | signal input in[k]; 508 | signal input p[k]; 509 | signal output out[k]; 510 | 511 | // length k 512 | var inv[100] = mod_inv(n, k, in, p); 513 | for (var i = 0; i < k; i++) { 514 | out[i] <-- inv[i]; 515 | } 516 | component range_checks[k]; 517 | for (var i = 0; i < k; i++) { 518 | range_checks[i] = Num2Bits(n); 519 | range_checks[i].in <== out[i]; 520 | } 521 | 522 | component mult = BigMult(n, k); 523 | for (var i = 0; i < k; i++) { 524 | mult.a[i] <== in[i]; 525 | mult.b[i] <== out[i]; 526 | } 527 | component mod = BigMod(n, k); 528 | for (var i = 0; i < 2 * k; i++) { 529 | mod.a[i] <== mult.out[i]; 530 | } 531 | for (var i = 0; i < k; i++) { 532 | mod.b[i] <== p[i]; 533 | } 534 | mod.mod[0] === 1; 535 | for (var i = 1; i < k; i++) { 536 | mod.mod[i] === 0; 537 | } 538 | } 539 | 540 | // in[i] contains values in the range -2^(m-1) to 2^(m-1) 541 | // constrain that in[] as a big integer is zero 542 | // each limbs is n bits 543 | template CheckCarryToZero(n, m, k) { 544 | assert(k >= 2); 545 | 546 | var EPSILON = 3; 547 | 548 | signal input in[k]; 549 | 550 | signal carry[k]; 551 | component carryRangeChecks[k]; 552 | for (var i = 0; i < k-1; i++){ 553 | carryRangeChecks[i] = Num2Bits(m + EPSILON - n); 554 | if( i == 0 ){ 555 | carry[i] <-- in[i] / (1<>shr) 10 | signal input a[n]; 11 | signal input b[n]; 12 | signal output out[n]; 13 | var i; 14 | 15 | component aux0 = ShR(64, shr); 16 | for (i=0; i<64; i++) { 17 | aux0.in[i] <== a[i]; 18 | } 19 | component aux1 = ShL(64, shl); 20 | for (i=0; i<64; i++) { 21 | aux1.in[i] <== a[i]; 22 | } 23 | component aux2 = OrArray(64); 24 | for (i=0; i<64; i++) { 25 | aux2.a[i] <== aux0.out[i]; 26 | aux2.b[i] <== aux1.out[i]; 27 | } 28 | component aux3 = XorArray(64); 29 | for (i=0; i<64; i++) { 30 | aux3.a[i] <== b[i]; 31 | aux3.b[i] <== aux2.out[i]; 32 | } 33 | for (i=0; i<64; i++) { 34 | out[i] <== aux3.out[i]; 35 | } 36 | } 37 | 38 | template Theta() { 39 | signal input in[25*64]; 40 | signal output out[25*64]; 41 | 42 | var i; 43 | 44 | component c0 = Xor5(64); 45 | for (i=0; i<64; i++) { 46 | c0.a[i] <== in[i]; 47 | c0.b[i] <== in[5*64+i]; 48 | c0.c[i] <== in[10*64+i]; 49 | c0.d[i] <== in[15*64+i]; 50 | c0.e[i] <== in[20*64+i]; 51 | } 52 | 53 | component c1 = Xor5(64); 54 | for (i=0; i<64; i++) { 55 | c1.a[i] <== in[1*64+i]; 56 | c1.b[i] <== in[6*64+i]; 57 | c1.c[i] <== in[11*64+i]; 58 | c1.d[i] <== in[16*64+i]; 59 | c1.e[i] <== in[21*64+i]; 60 | } 61 | 62 | component c2 = Xor5(64); 63 | for (i=0; i<64; i++) { 64 | c2.a[i] <== in[2*64+i]; 65 | c2.b[i] <== in[7*64+i]; 66 | c2.c[i] <== in[12*64+i]; 67 | c2.d[i] <== in[17*64+i]; 68 | c2.e[i] <== in[22*64+i]; 69 | } 70 | 71 | component c3 = Xor5(64); 72 | for (i=0; i<64; i++) { 73 | c3.a[i] <== in[3*64+i]; 74 | c3.b[i] <== in[8*64+i]; 75 | c3.c[i] <== in[13*64+i]; 76 | c3.d[i] <== in[18*64+i]; 77 | c3.e[i] <== in[23*64+i]; 78 | } 79 | 80 | component c4 = Xor5(64); 81 | for (i=0; i<64; i++) { 82 | c4.a[i] <== in[4*64+i]; 83 | c4.b[i] <== in[9*64+i]; 84 | c4.c[i] <== in[14*64+i]; 85 | c4.d[i] <== in[19*64+i]; 86 | c4.e[i] <== in[24*64+i]; 87 | } 88 | 89 | // d = c4 ^ (c1<<1 | c1>>(64-1)) 90 | component d0 = D(64, 1, 64-1); 91 | for (i=0; i<64; i++) { 92 | d0.a[i] <== c1.out[i]; 93 | d0.b[i] <== c4.out[i]; 94 | } 95 | // r[0] = a[0] ^ d 96 | component r0 = XorArray(64); 97 | for (i=0; i<64; i++) { 98 | r0.a[i] <== in[i]; 99 | r0.b[i] <== d0.out[i]; 100 | } 101 | for (i=0; i<64; i++) { 102 | out[i] <== r0.out[i]; 103 | } 104 | // r[5] = a[5] ^ d 105 | component r5 = XorArray(64); 106 | for (i=0; i<64; i++) { 107 | r5.a[i] <== in[5*64+i]; 108 | r5.b[i] <== d0.out[i]; 109 | } 110 | for (i=0; i<64; i++) { 111 | out[5*64+i] <== r5.out[i]; 112 | } 113 | // r[10] = a[10] ^ d 114 | component r10 = XorArray(64); 115 | for (i=0; i<64; i++) { 116 | r10.a[i] <== in[10*64+i]; 117 | r10.b[i] <== d0.out[i]; 118 | } 119 | for (i=0; i<64; i++) { 120 | out[10*64+i] <== r10.out[i]; 121 | } 122 | // r[15] = a[15] ^ d 123 | component r15 = XorArray(64); 124 | for (i=0; i<64; i++) { 125 | r15.a[i] <== in[15*64+i]; 126 | r15.b[i] <== d0.out[i]; 127 | } 128 | for (i=0; i<64; i++) { 129 | out[15*64+i] <== r15.out[i]; 130 | } 131 | // r[20] = a[20] ^ d 132 | component r20 = XorArray(64); 133 | for (i=0; i<64; i++) { 134 | r20.a[i] <== in[20*64+i]; 135 | r20.b[i] <== d0.out[i]; 136 | } 137 | for (i=0; i<64; i++) { 138 | out[20*64+i] <== r20.out[i]; 139 | } 140 | 141 | // d = c0 ^ (c2<<1 | c2>>(64-1)) 142 | component d1 = D(64, 1, 64-1); 143 | for (i=0; i<64; i++) { 144 | d1.a[i] <== c2.out[i]; 145 | d1.b[i] <== c0.out[i]; 146 | } 147 | // r[1] = a[1] ^ d 148 | component r1 = XorArray(64); 149 | for (i=0; i<64; i++) { 150 | r1.a[i] <== in[1*64+i]; 151 | r1.b[i] <== d1.out[i]; 152 | } 153 | for (i=0; i<64; i++) { 154 | out[1*64+i] <== r1.out[i]; 155 | } 156 | // r[6] = a[6] ^ d 157 | component r6 = XorArray(64); 158 | for (i=0; i<64; i++) { 159 | r6.a[i] <== in[6*64+i]; 160 | r6.b[i] <== d1.out[i]; 161 | } 162 | for (i=0; i<64; i++) { 163 | out[6*64+i] <== r6.out[i]; 164 | } 165 | // r[11] = a[11] ^ d 166 | component r11 = XorArray(64); 167 | for (i=0; i<64; i++) { 168 | r11.a[i] <== in[11*64+i]; 169 | r11.b[i] <== d1.out[i]; 170 | } 171 | for (i=0; i<64; i++) { 172 | out[11*64+i] <== r11.out[i]; 173 | } 174 | // r[16] = a[16] ^ d 175 | component r16 = XorArray(64); 176 | for (i=0; i<64; i++) { 177 | r16.a[i] <== in[16*64+i]; 178 | r16.b[i] <== d1.out[i]; 179 | } 180 | for (i=0; i<64; i++) { 181 | out[16*64+i] <== r16.out[i]; 182 | } 183 | // r[21] = a[21] ^ d 184 | component r21 = XorArray(64); 185 | for (i=0; i<64; i++) { 186 | r21.a[i] <== in[21*64+i]; 187 | r21.b[i] <== d1.out[i]; 188 | } 189 | for (i=0; i<64; i++) { 190 | out[21*64+i] <== r21.out[i]; 191 | } 192 | 193 | // d = c1 ^ (c3<<1 | c3>>(64-1)) 194 | component d2 = D(64, 1, 64-1); 195 | for (i=0; i<64; i++) { 196 | d2.a[i] <== c3.out[i]; 197 | d2.b[i] <== c1.out[i]; 198 | } 199 | // r[2] = a[2] ^ d 200 | component r2 = XorArray(64); 201 | for (i=0; i<64; i++) { 202 | r2.a[i] <== in[2*64+i]; 203 | r2.b[i] <== d2.out[i]; 204 | } 205 | for (i=0; i<64; i++) { 206 | out[2*64+i] <== r2.out[i]; 207 | } 208 | // r[7] = a[7] ^ d 209 | component r7 = XorArray(64); 210 | for (i=0; i<64; i++) { 211 | r7.a[i] <== in[7*64+i]; 212 | r7.b[i] <== d2.out[i]; 213 | } 214 | for (i=0; i<64; i++) { 215 | out[7*64+i] <== r7.out[i]; 216 | } 217 | // r[12] = a[12] ^ d 218 | component r12 = XorArray(64); 219 | for (i=0; i<64; i++) { 220 | r12.a[i] <== in[12*64+i]; 221 | r12.b[i] <== d2.out[i]; 222 | } 223 | for (i=0; i<64; i++) { 224 | out[12*64+i] <== r12.out[i]; 225 | } 226 | // r[17] = a[17] ^ d 227 | component r17 = XorArray(64); 228 | for (i=0; i<64; i++) { 229 | r17.a[i] <== in[17*64+i]; 230 | r17.b[i] <== d2.out[i]; 231 | } 232 | for (i=0; i<64; i++) { 233 | out[17*64+i] <== r17.out[i]; 234 | } 235 | // r[22] = a[22] ^ d 236 | component r22 = XorArray(64); 237 | for (i=0; i<64; i++) { 238 | r22.a[i] <== in[22*64+i]; 239 | r22.b[i] <== d2.out[i]; 240 | } 241 | for (i=0; i<64; i++) { 242 | out[22*64+i] <== r22.out[i]; 243 | } 244 | 245 | // d = c2 ^ (c4<<1 | c4>>(64-1)) 246 | component d3 = D(64, 1, 64-1); 247 | for (i=0; i<64; i++) { 248 | d3.a[i] <== c4.out[i]; 249 | d3.b[i] <== c2.out[i]; 250 | } 251 | // r[3] = a[3] ^ d 252 | component r3 = XorArray(64); 253 | for (i=0; i<64; i++) { 254 | r3.a[i] <== in[3*64+i]; 255 | r3.b[i] <== d3.out[i]; 256 | } 257 | for (i=0; i<64; i++) { 258 | out[3*64+i] <== r3.out[i]; 259 | } 260 | // r[8] = a[8] ^ d 261 | component r8 = XorArray(64); 262 | for (i=0; i<64; i++) { 263 | r8.a[i] <== in[8*64+i]; 264 | r8.b[i] <== d3.out[i]; 265 | } 266 | for (i=0; i<64; i++) { 267 | out[8*64+i] <== r8.out[i]; 268 | } 269 | // r[13] = a[13] ^ d 270 | component r13 = XorArray(64); 271 | for (i=0; i<64; i++) { 272 | r13.a[i] <== in[13*64+i]; 273 | r13.b[i] <== d3.out[i]; 274 | } 275 | for (i=0; i<64; i++) { 276 | out[13*64+i] <== r13.out[i]; 277 | } 278 | // r[18] = a[18] ^ d 279 | component r18 = XorArray(64); 280 | for (i=0; i<64; i++) { 281 | r18.a[i] <== in[18*64+i]; 282 | r18.b[i] <== d3.out[i]; 283 | } 284 | for (i=0; i<64; i++) { 285 | out[18*64+i] <== r18.out[i]; 286 | } 287 | // r[23] = a[23] ^ d 288 | component r23 = XorArray(64); 289 | for (i=0; i<64; i++) { 290 | r23.a[i] <== in[23*64+i]; 291 | r23.b[i] <== d3.out[i]; 292 | } 293 | for (i=0; i<64; i++) { 294 | out[23*64+i] <== r23.out[i]; 295 | } 296 | 297 | // d = c3 ^ (c0<<1 | c0>>(64-1)) 298 | component d4 = D(64, 1, 64-1); 299 | for (i=0; i<64; i++) { 300 | d4.a[i] <== c0.out[i]; 301 | d4.b[i] <== c3.out[i]; 302 | } 303 | // r[4] = a[4] ^ d 304 | component r4 = XorArray(64); 305 | for (i=0; i<64; i++) { 306 | r4.a[i] <== in[4*64+i]; 307 | r4.b[i] <== d4.out[i]; 308 | } 309 | for (i=0; i<64; i++) { 310 | out[4*64+i] <== r4.out[i]; 311 | } 312 | // r[9] = a[9] ^ d 313 | component r9 = XorArray(64); 314 | for (i=0; i<64; i++) { 315 | r9.a[i] <== in[9*64+i]; 316 | r9.b[i] <== d4.out[i]; 317 | } 318 | for (i=0; i<64; i++) { 319 | out[9*64+i] <== r9.out[i]; 320 | } 321 | // r[14] = a[14] ^ d 322 | component r14 = XorArray(64); 323 | for (i=0; i<64; i++) { 324 | r14.a[i] <== in[14*64+i]; 325 | r14.b[i] <== d4.out[i]; 326 | } 327 | for (i=0; i<64; i++) { 328 | out[14*64+i] <== r14.out[i]; 329 | } 330 | // r[19] = a[19] ^ d 331 | component r19 = XorArray(64); 332 | for (i=0; i<64; i++) { 333 | r19.a[i] <== in[19*64+i]; 334 | r19.b[i] <== d4.out[i]; 335 | } 336 | for (i=0; i<64; i++) { 337 | out[19*64+i] <== r19.out[i]; 338 | } 339 | // r[24] = a[24] ^ d 340 | component r24 = XorArray(64); 341 | for (i=0; i<64; i++) { 342 | r24.a[i] <== in[24*64+i]; 343 | r24.b[i] <== d4.out[i]; 344 | } 345 | for (i=0; i<64; i++) { 346 | out[24*64+i] <== r24.out[i]; 347 | } 348 | } 349 | 350 | // RhoPi 351 | 352 | template stepRhoPi(shl, shr) { 353 | // out = a<>shr 354 | signal input a[64]; 355 | signal output out[64]; 356 | var i; 357 | 358 | component aux0 = ShR(64, shr); 359 | for (i=0; i<64; i++) { 360 | aux0.in[i] <== a[i]; 361 | } 362 | component aux1 = ShL(64, shl); 363 | for (i=0; i<64; i++) { 364 | aux1.in[i] <== a[i]; 365 | } 366 | component aux2 = OrArray(64); 367 | for (i=0; i<64; i++) { 368 | aux2.a[i] <== aux0.out[i]; 369 | aux2.b[i] <== aux1.out[i]; 370 | } 371 | for (i=0; i<64; i++) { 372 | out[i] <== aux2.out[i]; 373 | } 374 | } 375 | template RhoPi() { 376 | signal input in[25*64]; 377 | signal output out[25*64]; 378 | 379 | var i; 380 | 381 | // r[10] = a[1]<<1|a[1]>>(64-1) 382 | component s10 = stepRhoPi(1, 64-1); 383 | for (i=0; i<64; i++) { 384 | s10.a[i] <== in[1*64+i]; 385 | } 386 | // r[7] = a[10]<<3|a[10]>>(64-3) 387 | component s7 = stepRhoPi(3, 64-3); 388 | for (i=0; i<64; i++) { 389 | s7.a[i] <== in[10*64+i]; 390 | } 391 | // r[11] = a[7]<<6|a[7]>>(64-6) 392 | component s11 = stepRhoPi(6, 64-6); 393 | for (i=0; i<64; i++) { 394 | s11.a[i] <== in[7*64+i]; 395 | } 396 | // r[17] = a[11]<<10|a[11]>>(64-10) 397 | component s17 = stepRhoPi(10, 64-10); 398 | for (i=0; i<64; i++) { 399 | s17.a[i] <== in[11*64+i]; 400 | } 401 | // r[18] = a[17]<<15|a[17]>>(64-15) 402 | component s18 = stepRhoPi(15, 64-15); 403 | for (i=0; i<64; i++) { 404 | s18.a[i] <== in[17*64+i]; 405 | } 406 | // r[3] = a[18]<<21|a[18]>>(64-21) 407 | component s3 = stepRhoPi(21, 64-21); 408 | for (i=0; i<64; i++) { 409 | s3.a[i] <== in[18*64+i]; 410 | } 411 | // r[5] = a[3]<<28|a[3]>>(64-28) 412 | component s5 = stepRhoPi(28, 64-28); 413 | for (i=0; i<64; i++) { 414 | s5.a[i] <== in[3*64+i]; 415 | } 416 | // r[16] = a[5]<<36|a[5]>>(64-36) 417 | component s16 = stepRhoPi(36, 64-36); 418 | for (i=0; i<64; i++) { 419 | s16.a[i] <== in[5*64+i]; 420 | } 421 | // r[8] = a[16]<<45|a[16]>>(64-45) 422 | component s8 = stepRhoPi(45, 64-45); 423 | for (i=0; i<64; i++) { 424 | s8.a[i] <== in[16*64+i]; 425 | } 426 | // r[21] = a[8]<<55|a[8]>>(64-55) 427 | component s21 = stepRhoPi(55, 64-55); 428 | for (i=0; i<64; i++) { 429 | s21.a[i] <== in[8*64+i]; 430 | } 431 | // r[24] = a[21]<<2|a[21]>>(64-2) 432 | component s24 = stepRhoPi(2, 64-2); 433 | for (i=0; i<64; i++) { 434 | s24.a[i] <== in[21*64+i]; 435 | } 436 | // r[4] = a[24]<<14|a[24]>>(64-14) 437 | component s4 = stepRhoPi(14, 64-14); 438 | for (i=0; i<64; i++) { 439 | s4.a[i] <== in[24*64+i]; 440 | } 441 | // r[15] = a[4]<<27|a[4]>>(64-27) 442 | component s15 = stepRhoPi(27, 64-27); 443 | for (i=0; i<64; i++) { 444 | s15.a[i] <== in[4*64+i]; 445 | } 446 | // r[23] = a[15]<<41|a[15]>>(64-41) 447 | component s23 = stepRhoPi(41, 64-41); 448 | for (i=0; i<64; i++) { 449 | s23.a[i] <== in[15*64+i]; 450 | } 451 | // r[19] = a[23]<<56|a[23]>>(64-56) 452 | component s19 = stepRhoPi(56, 64-56); 453 | for (i=0; i<64; i++) { 454 | s19.a[i] <== in[23*64+i]; 455 | } 456 | // r[13] = a[19]<<8|a[19]>>(64-8) 457 | component s13 = stepRhoPi(8, 64-8); 458 | for (i=0; i<64; i++) { 459 | s13.a[i] <== in[19*64+i]; 460 | } 461 | // r[12] = a[13]<<25|a[13]>>(64-25) 462 | component s12 = stepRhoPi(25, 64-25); 463 | for (i=0; i<64; i++) { 464 | s12.a[i] <== in[13*64+i]; 465 | } 466 | // r[2] = a[12]<<43|a[12]>>(64-43) 467 | component s2 = stepRhoPi(43, 64-43); 468 | for (i=0; i<64; i++) { 469 | s2.a[i] <== in[12*64+i]; 470 | } 471 | // r[20] = a[2]<<62|a[2]>>(64-62) 472 | component s20 = stepRhoPi(62, 64-62); 473 | for (i=0; i<64; i++) { 474 | s20.a[i] <== in[2*64+i]; 475 | } 476 | // r[14] = a[20]<<18|a[20]>>(64-18) 477 | component s14 = stepRhoPi(18, 64-18); 478 | for (i=0; i<64; i++) { 479 | s14.a[i] <== in[20*64+i]; 480 | } 481 | // r[22] = a[14]<<39|a[14]>>(64-39) 482 | component s22 = stepRhoPi(39, 64-39); 483 | for (i=0; i<64; i++) { 484 | s22.a[i] <== in[14*64+i]; 485 | } 486 | // r[9] = a[22]<<61|a[22]>>(64-61) 487 | component s9 = stepRhoPi(61, 64-61); 488 | for (i=0; i<64; i++) { 489 | s9.a[i] <== in[22*64+i]; 490 | } 491 | // r[6] = a[9]<<20|a[9]>>(64-20) 492 | component s6 = stepRhoPi(20, 64-20); 493 | for (i=0; i<64; i++) { 494 | s6.a[i] <== in[9*64+i]; 495 | } 496 | // r[1] = a[6]<<44|a[6]>>(64-44) 497 | component s1 = stepRhoPi(44, 64-44); 498 | for (i=0; i<64; i++) { 499 | s1.a[i] <== in[6*64+i]; 500 | } 501 | 502 | for (i=0; i<64; i++) { 503 | out[i] <== in[i]; 504 | out[10*64+i] <== s10.out[i]; 505 | out[7*64+i] <== s7.out[i]; 506 | out[11*64+i] <== s11.out[i]; 507 | out[17*64+i] <== s17.out[i]; 508 | out[18*64+i] <== s18.out[i]; 509 | out[3*64+i] <== s3.out[i]; 510 | out[5*64+i] <== s5.out[i]; 511 | out[16*64+i] <== s16.out[i]; 512 | out[8*64+i] <== s8.out[i]; 513 | out[21*64+i] <== s21.out[i]; 514 | out[24*64+i] <== s24.out[i]; 515 | out[4*64+i] <== s4.out[i]; 516 | out[15*64+i] <== s15.out[i]; 517 | out[23*64+i] <== s23.out[i]; 518 | out[19*64+i] <== s19.out[i]; 519 | out[13*64+i] <== s13.out[i]; 520 | out[12*64+i] <== s12.out[i]; 521 | out[2*64+i] <== s2.out[i]; 522 | out[20*64+i] <== s20.out[i]; 523 | out[14*64+i] <== s14.out[i]; 524 | out[22*64+i] <== s22.out[i]; 525 | out[9*64+i] <== s9.out[i]; 526 | out[6*64+i] <== s6.out[i]; 527 | out[1*64+i] <== s1.out[i]; 528 | } 529 | } 530 | 531 | 532 | // Chi 533 | 534 | template stepChi() { 535 | // out = a ^ (^b) & c 536 | signal input a[64]; 537 | signal input b[64]; 538 | signal input c[64]; 539 | signal output out[64]; 540 | var i; 541 | 542 | // ^b 543 | component bXor = XorArraySingle(64); 544 | for (i=0; i<64; i++) { 545 | bXor.a[i] <== b[i]; 546 | } 547 | // (^b)&c 548 | component bc = AndArray(64); 549 | for (i=0; i<64; i++) { 550 | bc.a[i] <== bXor.out[i]; 551 | bc.b[i] <== c[i]; 552 | } 553 | // a^(^b)&c 554 | component abc = XorArray(64); 555 | for (i=0; i<64; i++) { 556 | abc.a[i] <== a[i]; 557 | abc.b[i] <== bc.out[i]; 558 | } 559 | for (i=0; i<64; i++) { 560 | out[i] <== abc.out[i]; 561 | } 562 | } 563 | 564 | template Chi() { 565 | signal input in[25*64]; 566 | signal output out[25*64]; 567 | 568 | var i; 569 | 570 | component r0 = stepChi(); 571 | for (i=0; i<64; i++) { 572 | r0.a[i] <== in[i]; 573 | r0.b[i] <== in[1*64+i]; 574 | r0.c[i] <== in[2*64+i]; 575 | } 576 | component r1 = stepChi(); 577 | for (i=0; i<64; i++) { 578 | r1.a[i] <== in[1*64+i]; 579 | r1.b[i] <== in[2*64+i]; 580 | r1.c[i] <== in[3*64+i]; 581 | } 582 | component r2 = stepChi(); 583 | for (i=0; i<64; i++) { 584 | r2.a[i] <== in[2*64+i]; 585 | r2.b[i] <== in[3*64+i]; 586 | r2.c[i] <== in[4*64+i]; 587 | } 588 | component r3 = stepChi(); 589 | for (i=0; i<64; i++) { 590 | r3.a[i] <== in[3*64+i]; 591 | r3.b[i] <== in[4*64+i]; 592 | r3.c[i] <== in[0*64+i]; 593 | } 594 | component r4 = stepChi(); 595 | for (i=0; i<64; i++) { 596 | r4.a[i] <== in[4*64+i]; 597 | r4.b[i] <== in[i]; 598 | r4.c[i] <== in[1*64+i]; 599 | } 600 | 601 | component r5 = stepChi(); 602 | for (i=0; i<64; i++) { 603 | r5.a[i] <== in[5*64+i]; 604 | r5.b[i] <== in[6*64+i]; 605 | r5.c[i] <== in[7*64+i]; 606 | } 607 | component r6 = stepChi(); 608 | for (i=0; i<64; i++) { 609 | r6.a[i] <== in[6*64+i]; 610 | r6.b[i] <== in[7*64+i]; 611 | r6.c[i] <== in[8*64+i]; 612 | } 613 | component r7 = stepChi(); 614 | for (i=0; i<64; i++) { 615 | r7.a[i] <== in[7*64+i]; 616 | r7.b[i] <== in[8*64+i]; 617 | r7.c[i] <== in[9*64+i]; 618 | } 619 | component r8 = stepChi(); 620 | for (i=0; i<64; i++) { 621 | r8.a[i] <== in[8*64+i]; 622 | r8.b[i] <== in[9*64+i]; 623 | r8.c[i] <== in[5*64+i]; 624 | } 625 | component r9 = stepChi(); 626 | for (i=0; i<64; i++) { 627 | r9.a[i] <== in[9*64+i]; 628 | r9.b[i] <== in[5*64+i]; 629 | r9.c[i] <== in[6*64+i]; 630 | } 631 | 632 | component r10 = stepChi(); 633 | for (i=0; i<64; i++) { 634 | r10.a[i] <== in[10*64+i]; 635 | r10.b[i] <== in[11*64+i]; 636 | r10.c[i] <== in[12*64+i]; 637 | } 638 | component r11 = stepChi(); 639 | for (i=0; i<64; i++) { 640 | r11.a[i] <== in[11*64+i]; 641 | r11.b[i] <== in[12*64+i]; 642 | r11.c[i] <== in[13*64+i]; 643 | } 644 | component r12 = stepChi(); 645 | for (i=0; i<64; i++) { 646 | r12.a[i] <== in[12*64+i]; 647 | r12.b[i] <== in[13*64+i]; 648 | r12.c[i] <== in[14*64+i]; 649 | } 650 | component r13 = stepChi(); 651 | for (i=0; i<64; i++) { 652 | r13.a[i] <== in[13*64+i]; 653 | r13.b[i] <== in[14*64+i]; 654 | r13.c[i] <== in[10*64+i]; 655 | } 656 | component r14 = stepChi(); 657 | for (i=0; i<64; i++) { 658 | r14.a[i] <== in[14*64+i]; 659 | r14.b[i] <== in[10*64+i]; 660 | r14.c[i] <== in[11*64+i]; 661 | } 662 | 663 | component r15 = stepChi(); 664 | for (i=0; i<64; i++) { 665 | r15.a[i] <== in[15*64+i]; 666 | r15.b[i] <== in[16*64+i]; 667 | r15.c[i] <== in[17*64+i]; 668 | } 669 | component r16 = stepChi(); 670 | for (i=0; i<64; i++) { 671 | r16.a[i] <== in[16*64+i]; 672 | r16.b[i] <== in[17*64+i]; 673 | r16.c[i] <== in[18*64+i]; 674 | } 675 | component r17 = stepChi(); 676 | for (i=0; i<64; i++) { 677 | r17.a[i] <== in[17*64+i]; 678 | r17.b[i] <== in[18*64+i]; 679 | r17.c[i] <== in[19*64+i]; 680 | } 681 | component r18 = stepChi(); 682 | for (i=0; i<64; i++) { 683 | r18.a[i] <== in[18*64+i]; 684 | r18.b[i] <== in[19*64+i]; 685 | r18.c[i] <== in[15*64+i]; 686 | } 687 | component r19 = stepChi(); 688 | for (i=0; i<64; i++) { 689 | r19.a[i] <== in[19*64+i]; 690 | r19.b[i] <== in[15*64+i]; 691 | r19.c[i] <== in[16*64+i]; 692 | } 693 | 694 | component r20 = stepChi(); 695 | for (i=0; i<64; i++) { 696 | r20.a[i] <== in[20*64+i]; 697 | r20.b[i] <== in[21*64+i]; 698 | r20.c[i] <== in[22*64+i]; 699 | } 700 | component r21 = stepChi(); 701 | for (i=0; i<64; i++) { 702 | r21.a[i] <== in[21*64+i]; 703 | r21.b[i] <== in[22*64+i]; 704 | r21.c[i] <== in[23*64+i]; 705 | } 706 | component r22 = stepChi(); 707 | for (i=0; i<64; i++) { 708 | r22.a[i] <== in[22*64+i]; 709 | r22.b[i] <== in[23*64+i]; 710 | r22.c[i] <== in[24*64+i]; 711 | } 712 | component r23 = stepChi(); 713 | for (i=0; i<64; i++) { 714 | r23.a[i] <== in[23*64+i]; 715 | r23.b[i] <== in[24*64+i]; 716 | r23.c[i] <== in[20*64+i]; 717 | } 718 | component r24 = stepChi(); 719 | for (i=0; i<64; i++) { 720 | r24.a[i] <== in[24*64+i]; 721 | r24.b[i] <== in[20*64+i]; 722 | r24.c[i] <== in[21*64+i]; 723 | } 724 | 725 | for (i=0; i<64; i++) { 726 | out[i] <== r0.out[i]; 727 | out[1*64+i] <== r1.out[i]; 728 | out[2*64+i] <== r2.out[i]; 729 | out[3*64+i] <== r3.out[i]; 730 | out[4*64+i] <== r4.out[i]; 731 | 732 | out[5*64+i] <== r5.out[i]; 733 | out[6*64+i] <== r6.out[i]; 734 | out[7*64+i] <== r7.out[i]; 735 | out[8*64+i] <== r8.out[i]; 736 | out[9*64+i] <== r9.out[i]; 737 | 738 | out[10*64+i] <== r10.out[i]; 739 | out[11*64+i] <== r11.out[i]; 740 | out[12*64+i] <== r12.out[i]; 741 | out[13*64+i] <== r13.out[i]; 742 | out[14*64+i] <== r14.out[i]; 743 | 744 | out[15*64+i] <== r15.out[i]; 745 | out[16*64+i] <== r16.out[i]; 746 | out[17*64+i] <== r17.out[i]; 747 | out[18*64+i] <== r18.out[i]; 748 | out[19*64+i] <== r19.out[i]; 749 | 750 | out[20*64+i] <== r20.out[i]; 751 | out[21*64+i] <== r21.out[i]; 752 | out[22*64+i] <== r22.out[i]; 753 | out[23*64+i] <== r23.out[i]; 754 | out[24*64+i] <== r24.out[i]; 755 | } 756 | } 757 | 758 | // Iota 759 | 760 | template RC(r) { 761 | signal output out[64]; 762 | var rc[24] = [ 763 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 764 | 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, 765 | 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 766 | 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, 767 | 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 768 | 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 769 | 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, 770 | 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 771 | ]; 772 | for (var i=0; i<64; i++) { 773 | out[i] <== (rc[r] >> i) & 1; 774 | } 775 | } 776 | 777 | template Iota(r) { 778 | signal input in[25*64]; 779 | signal output out[25*64]; 780 | var i; 781 | 782 | component rc = RC(r); 783 | 784 | component iota = XorArray(64); 785 | for (var i=0; i<64; i++) { 786 | iota.a[i] <== in[i]; 787 | iota.b[i] <== rc.out[i]; 788 | } 789 | for (i=0; i<64; i++) { 790 | out[i] <== iota.out[i]; 791 | } 792 | for (i=64; i<25*64; i++) { 793 | out[i] <== in[i]; 794 | } 795 | } 796 | 797 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------