├── config.json ├── src ├── index.ts ├── bigint.ts ├── bigint.test.ts ├── g1_affine.ts ├── Add.ts ├── const.ts ├── g2.test.ts ├── g2_affine.ts ├── fq_provable.ts ├── groth16.ts ├── Add.test.ts ├── foreignFieldBn.test.ts ├── g1.test.ts ├── primeField.test.ts ├── g1_new.test.ts ├── fq_provable.test.ts ├── fq.test.ts ├── interact.ts ├── fp12.test.ts ├── fp2.test.ts ├── primeField.ts ├── g1_new.ts ├── fp6.test.ts ├── pairing.test.ts ├── fq2.ts ├── fq.ts ├── fp_mont.ts ├── g1.ts ├── g2_new.test.ts ├── g2_new.ts ├── fq2.test.ts ├── g2.ts ├── fp2.ts ├── fp6.ts ├── fp12.ts ├── fq6.ts ├── pairing.ts ├── fq12.ts ├── pairing_new.ts └── pairing_new.test.ts ├── .prettierrc ├── babel.config.cjs ├── .npmignore ├── .gitignore ├── .prettierignore ├── .gitattributes ├── .eslintrc.cjs ├── jest-resolver.cjs ├── jest.config.js ├── tsconfig.json ├── package.json ├── README.md └── LICENSE /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "deployAliases": {} 4 | } 5 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Add } from './Add.js'; 2 | 3 | export { Add }; 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "es5" 6 | } 7 | -------------------------------------------------------------------------------- /babel.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }]], 3 | }; 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # TypeScript files 2 | src 3 | 4 | # Editor 5 | .vscode 6 | 7 | # System 8 | .DS_Store 9 | 10 | # Never reveal your keys! 11 | keys 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NodeJS 2 | node_modules 3 | build 4 | coverage 5 | 6 | # Editor 7 | .vscode 8 | 9 | # System 10 | .DS_Store 11 | 12 | # Never commit keys to Git! 13 | keys 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # NodeJS 2 | node_modules 3 | build 4 | coverage 5 | .husky 6 | 7 | # Editor 8 | .vscode 9 | 10 | # System 11 | .DS_Store 12 | 13 | # Misc 14 | LICENSE 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Use line endings appropriate for the system. This prevents Git from 2 | # complaining about project template line endings when committing on Windows. 3 | * text=auto eol=lf 4 | -------------------------------------------------------------------------------- /src/bigint.ts: -------------------------------------------------------------------------------- 1 | import {Field, Poseidon} from 'o1js'; 2 | 3 | export default class PrimeField{ 4 | value: Field; 5 | 6 | add(y: Field): Field { 7 | return new Field(15); 8 | } 9 | 10 | constructor(x: Field) { 11 | this.value = Field(10); 12 | return; 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | jest: true, 7 | }, 8 | extends: [ 9 | 'eslint:recommended', 10 | 'plugin:@typescript-eslint/eslint-recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | 'plugin:o1js/recommended', 13 | ], 14 | parser: '@typescript-eslint/parser', 15 | parserOptions: { 16 | ecmaVersion: 'latest', 17 | }, 18 | plugins: ['@typescript-eslint', 'o1js'], 19 | rules: { 20 | 'no-constant-condition': 'off', 21 | 'prefer-const': 'off', 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /jest-resolver.cjs: -------------------------------------------------------------------------------- 1 | module.exports = (request, options) => { 2 | return options.defaultResolver(request, { 3 | ...options, 4 | packageFilter: (pkg) => { 5 | // When importing o1js, we specify the Node ESM import as Jest by default imports the web version 6 | if (pkg.name === 'o1js') { 7 | return { 8 | ...pkg, 9 | main: pkg.exports.node.import, 10 | }; 11 | } 12 | if (pkg.name === 'node-fetch') { 13 | return { ...pkg, main: pkg.main }; 14 | } 15 | return { 16 | ...pkg, 17 | main: pkg.module || pkg.main, 18 | }; 19 | }, 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */ 2 | export default { 3 | verbose: true, 4 | preset: 'ts-jest/presets/default-esm', 5 | testEnvironment: 'node', 6 | globals: { 7 | 'ts-jest': { 8 | useESM: true, 9 | }, 10 | }, 11 | testTimeout: 1_000_000, 12 | transform: { 13 | '^.+\\.(t)s$': 'ts-jest', 14 | '^.+\\.(j)s$': 'babel-jest', 15 | }, 16 | resolver: '/jest-resolver.cjs', 17 | transformIgnorePatterns: [ 18 | '/node_modules/(?!(tslib|o1js/node_modules/tslib))', 19 | ], 20 | modulePathIgnorePatterns: ['/build/'], 21 | moduleNameMapper: { 22 | '^(\\.{1,2}/.+)\\.js$': '$1', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2022", 5 | "lib": ["dom", "esnext"], 6 | "outDir": "./build", 7 | "rootDir": ".", 8 | "strict": true, 9 | "strictPropertyInitialization": false, // to enable generic constructors, e.g. on CircuitValue 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "esModuleInterop": true, 13 | "moduleResolution": "node", 14 | "experimentalDecorators": true, 15 | "emitDecoratorMetadata": true, 16 | "allowJs": true, 17 | "declaration": true, 18 | "sourceMap": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "allowSyntheticDefaultImports": true 21 | }, 22 | "include": ["./src"] 23 | } 24 | -------------------------------------------------------------------------------- /src/bigint.test.ts: -------------------------------------------------------------------------------- 1 | import {Field, Poseidon} from 'o1js'; 2 | import PrimeField from './bigint'; 3 | 4 | function hashField(preimage: Field) { 5 | let hash = Poseidon.hash([preimage]); 6 | console.log(hash) 7 | } 8 | 9 | describe('calculate', function() { 10 | it('add', function() { 11 | //console.log(Poseidon.hash([Field(0x2342), Field(0x333)])); 12 | console.log("hello"); 13 | let x = new PrimeField(Field(20)); 14 | console.log(x.value); 15 | console.log(Field(28948022309329048855892746252171976963363056481941560715954676764349967630336n)) 16 | }); 17 | }); 18 | 19 | // field element is at most 256 bit. 20 | // So, it would be easier to implement snark_prime_field with this 21 | // BigInt'e ihtiyacımız yok. 22 | // prime_field nereden implement edelim?? -------------------------------------------------------------------------------- /src/g1_affine.ts: -------------------------------------------------------------------------------- 1 | import Fq from "./fq"; 2 | import G1 from "./g1_new"; 3 | 4 | export default class G1Affine{ 5 | x: Fq; 6 | y: Fq; 7 | 8 | constructor(x: Fq, y: Fq) { 9 | // we can add checks later 10 | this.x = x; 11 | this.y = y; 12 | } 13 | 14 | to_proj() { 15 | return new G1( 16 | this.x, 17 | this.y, 18 | new Fq(1n) 19 | ); 20 | } 21 | 22 | static a = new Fq(0n); 23 | static b = new Fq(3n); 24 | 25 | static generator() { 26 | return new G1Affine( 27 | new Fq(1n), 28 | new Fq(2n), 29 | ); 30 | } 31 | 32 | static identity() { 33 | return new G1Affine( 34 | new Fq(0n), 35 | new Fq(1n) 36 | ) 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/Add.ts: -------------------------------------------------------------------------------- 1 | import { Field, SmartContract, state, State, method } from 'o1js'; 2 | 3 | /** 4 | * Basic Example 5 | * See https://docs.minaprotocol.com/zkapps for more info. 6 | * 7 | * The Add contract initializes the state variable 'num' to be a Field(1) value by default when deployed. 8 | * When the 'update' method is called, the Add contract adds Field(2) to its 'num' contract state. 9 | * 10 | * This file is safe to delete and replace with your own contract. 11 | */ 12 | export class Add extends SmartContract { 13 | @state(Field) num = State(); 14 | 15 | init() { 16 | super.init(); 17 | this.num.set(Field(1)); 18 | } 19 | 20 | @method update() { 21 | const currentState = this.num.getAndAssertEquals(); 22 | const newState = currentState.add(2); 23 | this.num.set(newState); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/const.ts: -------------------------------------------------------------------------------- 1 | // Canonical signed digit decomposition (Non-Adjacent form) of 6x₀+2 = 29793968203157093288 little endian 2 | export const NAF_DIGIT = [ 3 | 0, 4 | 0, 5 | 0, 6 | 1, 7 | 0, 8 | 1, 9 | 0, 10 | 2, 11 | 0, 12 | 0, 13 | 2, 14 | 0, 15 | 0, 16 | 0, 17 | 1, 18 | 0, 19 | 0, 20 | 2, 21 | 0, 22 | 2, 23 | 0, 24 | 0, 25 | 0, 26 | 1, 27 | 0, 28 | 2, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 2, 34 | 0, 35 | 0, 36 | 1, 37 | 0, 38 | 2, 39 | 0, 40 | 0, 41 | 1, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 2, 48 | 0, 49 | 0, 50 | 2, 51 | 0, 52 | 1, 53 | 0, 54 | 2, 55 | 0, 56 | 0, 57 | 0, 58 | 2, 59 | 0, 60 | 2, 61 | 0, 62 | 0, 63 | 0, 64 | 1, 65 | 0, 66 | 2, 67 | 0, 68 | 1 69 | ]; -------------------------------------------------------------------------------- /src/g2.test.ts: -------------------------------------------------------------------------------- 1 | import G2Group from './g2' 2 | 3 | 4 | describe('test bn254 g1', function() { 5 | 6 | // O + O = O 7 | it('Add bn254', function() { 8 | console.log("Add two bn254 group element"); 9 | let x = G2Group.zero(); 10 | let y = G2Group.zero(); 11 | 12 | let p = x.add(y); 13 | p.assertEquals(G2Group.zero()); 14 | 15 | }); 16 | 17 | // O + G = G 18 | it('Add bn254 v2', function() { 19 | console.log("Add zero and the generator"); 20 | //let p = G1Group.generator().add(G1Group.zero()); 21 | let p = G2Group.generator(); 22 | p = p.add(G2Group.zero()); 23 | console.log(p); 24 | console.log(G2Group.zero()); 25 | p.assertEquals(G2Group.generator()); 26 | console.log(p); 27 | }); 28 | 29 | // 2*G + G = 3G 30 | it('Add bn254 v3', function() { 31 | console.log("Test 2 * G + G = 3 * G"); 32 | let p = G2Group.generator().double(); 33 | let q = G2Group.generator(); 34 | 35 | let g3 = p.add(q); 36 | g3.assertEquals(G2Group.g_3()); 37 | }); 38 | }); -------------------------------------------------------------------------------- /src/g2_affine.ts: -------------------------------------------------------------------------------- 1 | import Fq from "./fq"; 2 | import Fq2 from "./fq2"; 3 | import G2 from "./g2_new"; 4 | 5 | export default class G2Affine{ 6 | x: Fq2; 7 | y: Fq2; 8 | 9 | constructor(x: Fq2, y: Fq2) { 10 | // we can add checks later 11 | this.x = x; 12 | this.y = y; 13 | } 14 | 15 | static a = new Fq2( 16 | new Fq(0n), 17 | new Fq(0n) 18 | ); 19 | 20 | static b = new Fq2( 21 | new Fq(19485874751759354771024239261021720505790618469301721065564631296452457478373n), 22 | new Fq(266929791119991161246907387137283842545076965332900288569378510910307636690n) 23 | ); 24 | 25 | static curve_constant_3b = new Fq2( 26 | new Fq(14681138511599513868579906292550611339979233093309515871315818100066920017953n), 27 | new Fq(800789373359973483740722161411851527635230895998700865708135532730922910070n) 28 | ); 29 | 30 | to_proj() { 31 | return new G2( 32 | this.x, 33 | this.y, 34 | new Fq2( 35 | new Fq(1n), 36 | new Fq(0n) 37 | ) 38 | ) 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "o1js-groth16", 3 | "version": "0.1.0", 4 | "description": "", 5 | "author": "", 6 | "license": "Apache-2.0", 7 | "keywords": [ 8 | "mina-zkapp", 9 | "mina-zk-app", 10 | "mina-dapp", 11 | "zkapp" 12 | ], 13 | "type": "module", 14 | "main": "build/src/index.js", 15 | "types": "build/src/index.d.ts", 16 | "scripts": { 17 | "build": "tsc", 18 | "buildw": "tsc --watch", 19 | "coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage", 20 | "format": "prettier --write --ignore-unknown **/*", 21 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", 22 | "testw": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch", 23 | "lint": "npx eslint src/* --fix" 24 | }, 25 | "devDependencies": { 26 | "@babel/preset-env": "^7.16.4", 27 | "@babel/preset-typescript": "^7.16.0", 28 | "@types/jest": "^27.0.3", 29 | "@typescript-eslint/eslint-plugin": "^5.5.0", 30 | "@typescript-eslint/parser": "^5.5.0", 31 | "eslint": "^8.7.0", 32 | "eslint-plugin-o1js": "^0.4.0", 33 | "jest": "^27.3.1", 34 | "prettier": "^2.3.2", 35 | "ts-jest": "^27.0.7", 36 | "typescript": "^4.7.2" 37 | }, 38 | "dependencies": { 39 | "@noble/curves": "^1.2.0", 40 | "o1js": "^0.14.2", 41 | "zkapp-cli": "^0.16.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mina zkApp: O1js Groth16 2 | 3 | This template uses TypeScript. 4 | 5 | ## What's the project? 6 | This project implements Groth16 Verifier using o1js using non-native pairing friendly elliptic curves together with pairing functions. 7 | 8 | Using Groth16 Verifier in o1js, other projects will be able to verify their groth16 circuits as Mina Smart Contracts. In other words, the projects built using Circom will be able to create a Groth16 verifier as a Mina Smart Contract using SnarkJS (generate the Verifier.ts in the SnarkJS, which will be usable in o1js) 9 | 10 | ## What's the progress? 11 | - While waiting for the "foreign field operations in o1js", PrimeField is implemented for BN254 prime field. (foreign-field in feat branch will be integrated or will be changed by adding Montgomery multiplication for faster operations) 12 | - Fp2, Fp6, Fp12 implemented (foreign-field in feat branch will be integrated) 13 | - Final exponentiation and Miller loop implemented. (Miller loop tests fails, will be fixed.) 14 | - Pairing.pair(G2Group, G1Group) is implemented, but bilinearity tests are not working correctly due to a mistake in the implementation (will be fixed) 15 | - Groth16 Verifier (will be fixed after the bilinearity tests are passed) 16 | 17 | ## How to build 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | ## How to run tests 24 | 25 | ```sh 26 | npm run test 27 | npm run testw # watch mode 28 | ``` 29 | 30 | ## How to run coverage 31 | 32 | ```sh 33 | npm run coverage 34 | ``` 35 | 36 | ## License 37 | 38 | [Apache-2.0](LICENSE) 39 | -------------------------------------------------------------------------------- /src/fq_provable.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Fq.ts uses {ForeignField, Field3} from {Gadgets} 3 | */ 4 | import { Field } from "o1js"; 5 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 6 | 7 | const bn254_prime = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; 8 | const zero = Field3.from(0n); 9 | 10 | export default class Fq{ 11 | value: Field3; 12 | 13 | constructor(value: Field3) { 14 | this.value = value; 15 | } 16 | 17 | add(x: Fq) { 18 | return new Fq( 19 | ForeignField.add(this.value, x.value, bn254_prime) 20 | ); 21 | } 22 | 23 | sub(x: Fq) { 24 | return new Fq( 25 | ForeignField.sub(this.value, x.value, bn254_prime) 26 | ); 27 | } 28 | 29 | // For logging reasons, will not be used in the circuit. 30 | toBigInt() { 31 | return Field3.toBigint(this.value); 32 | } 33 | 34 | mul(x: Fq) { 35 | return new Fq( 36 | ForeignField.mul(this.value, x.value, bn254_prime) 37 | ); 38 | } 39 | 40 | inv(){ 41 | return new Fq( 42 | ForeignField.inv(this.value, bn254_prime) 43 | ); 44 | } 45 | 46 | double() { 47 | return new Fq( 48 | ForeignField.add(this.value, this.value, bn254_prime) 49 | ); 50 | } 51 | 52 | square() { 53 | return new Fq( 54 | ForeignField.mul(this.value, this.value, bn254_prime) 55 | ); 56 | } 57 | 58 | div(x: Fq) { 59 | return new Fq( 60 | ForeignField.div(this.value, x.value, bn254_prime) 61 | ); 62 | } 63 | 64 | static zero() { 65 | new Fq( 66 | zero 67 | ) 68 | } 69 | 70 | // need test for this 71 | // is it provable 72 | neg() { 73 | return new Fq( 74 | ForeignField.sub(zero, this.value, bn254_prime) 75 | ); 76 | } 77 | 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/groth16.ts: -------------------------------------------------------------------------------- 1 | import {Field, Group, Poseidon, Scalar} from 'o1js'; 2 | import Fp12 from './fp12'; 3 | import Fp2 from './fp2'; 4 | import Pairing from './pairing'; 5 | import G2Group from './g2'; 6 | import { Pallas } from 'o1js/dist/node/bindings/crypto/elliptic_curve'; 7 | 8 | 9 | // struct VerifyingKey 10 | // struct Proof 11 | // function that brings VerifyingKey -> Constructor 12 | // pairing function that uses pairings 13 | // verifyProof function 14 | 15 | 16 | class VerifyingKey { 17 | alfa1: Group; 18 | beta2: G2Group; 19 | gamma2: G2Group; 20 | delta2: G2Group; 21 | IC: Group[]; 22 | 23 | constructor(alfa1: Group, beta2: G2Group, gamma2: G2Group, delta2: G2Group, IC: Group[]) { 24 | this.alfa1 = alfa1; 25 | this.beta2 = beta2; 26 | this.gamma2 = gamma2; 27 | this.delta2 = delta2; 28 | this.IC = IC; 29 | } 30 | } 31 | 32 | class Proof { 33 | A: Group; 34 | B: G2Group; 35 | C: Group; 36 | 37 | constructor(A: Group, B: G2Group, C: Group) { 38 | this.A = A; 39 | this.B = B; 40 | this.C = C; 41 | } 42 | } 43 | 44 | export default function verifyGroth16(vkVerifier: VerifyingKey, publicSignals: Field[], _proof: Proof){ 45 | let vk_x = Group({x: Field(0), y: Field(0)}); 46 | vk_x = vk_x.add(vkVerifier.IC[0]); 47 | 48 | for(let i = 0; i < publicSignals.length; i++) { 49 | // scalar multiplication !not_implemented 50 | // let temp = vkVerifier.IC[i+1]. 51 | // scale function is scalar multiplication in the Pallas Curve 52 | // we need to implement a new scalar multiplication in BN254 G1Curve 53 | 54 | // TEMPORARY! FIX THE SCALAR MULTIPLICATION 55 | 56 | // let x = publicSignals[i]; 57 | // let temp: Group = vkVerifier.IC[i+1].scale(Scalar(x)); 58 | // Scale fonksiyonu scalar kullanıyor. Biz ise, field ile bunu implement edeceğiz. 59 | 60 | let temp: Group = new Group({x: Field(0), y:Field(0)}); 61 | vk_x = vk_x.add(temp); 62 | } 63 | 64 | // add the special pairing in here (Tornado-like pairing) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Add.test.ts: -------------------------------------------------------------------------------- 1 | import { Add } from './Add'; 2 | import { Field, Mina, PrivateKey, PublicKey, AccountUpdate } from 'o1js'; 3 | 4 | /* 5 | * This file specifies how to test the `Add` example smart contract. It is safe to delete this file and replace 6 | * with your own tests. 7 | * 8 | * See https://docs.minaprotocol.com/zkapps for more info. 9 | */ 10 | 11 | let proofsEnabled = false; 12 | 13 | describe('Add', () => { 14 | let deployerAccount: PublicKey, 15 | deployerKey: PrivateKey, 16 | senderAccount: PublicKey, 17 | senderKey: PrivateKey, 18 | zkAppAddress: PublicKey, 19 | zkAppPrivateKey: PrivateKey, 20 | zkApp: Add; 21 | 22 | beforeAll(async () => { 23 | if (proofsEnabled) await Add.compile(); 24 | }); 25 | 26 | beforeEach(() => { 27 | const Local = Mina.LocalBlockchain({ proofsEnabled }); 28 | Mina.setActiveInstance(Local); 29 | ({ privateKey: deployerKey, publicKey: deployerAccount } = 30 | Local.testAccounts[0]); 31 | ({ privateKey: senderKey, publicKey: senderAccount } = 32 | Local.testAccounts[1]); 33 | zkAppPrivateKey = PrivateKey.random(); 34 | zkAppAddress = zkAppPrivateKey.toPublicKey(); 35 | zkApp = new Add(zkAppAddress); 36 | }); 37 | 38 | async function localDeploy() { 39 | const txn = await Mina.transaction(deployerAccount, () => { 40 | AccountUpdate.fundNewAccount(deployerAccount); 41 | zkApp.deploy(); 42 | }); 43 | await txn.prove(); 44 | // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization 45 | await txn.sign([deployerKey, zkAppPrivateKey]).send(); 46 | } 47 | 48 | it('generates and deploys the `Add` smart contract', async () => { 49 | await localDeploy(); 50 | const num = zkApp.num.get(); 51 | expect(num).toEqual(Field(1)); 52 | }); 53 | 54 | it('correctly updates the num state on the `Add` smart contract', async () => { 55 | await localDeploy(); 56 | 57 | // update transaction 58 | const txn = await Mina.transaction(senderAccount, () => { 59 | zkApp.update(); 60 | }); 61 | await txn.prove(); 62 | await txn.sign([senderKey]).send(); 63 | 64 | const updatedNum = zkApp.num.get(); 65 | expect(updatedNum).toEqual(Field(3)); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /src/foreignFieldBn.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "o1js/dist/node/lib/errors.js"; 2 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 3 | 4 | 5 | describe('test ForeignField', function() { 6 | it('test foreign field', function() { 7 | //let x = new ForeignField(2n); 8 | let x = Field3.from(1n); 9 | let y = Field3.from(1n); 10 | let z = Field3.from(1n); 11 | 12 | console.log(x[0]); 13 | console.log(x[1].value); 14 | console.log(x[2].value); 15 | }); 16 | 17 | // 5n + 6n == 4n in mod 7n 18 | it('testing ForeignField.add() for 5n+6n == 4n mod 7n', function() { 19 | let x = Field3.from(5n); 20 | console.log(x); 21 | 22 | let y = Field3.from(6n); 23 | 24 | let z = Field3.toBigint(x); 25 | console.log(z); 26 | 27 | let res = ForeignField.add(x, y, 7n); 28 | let res_bigint = Field3.toBigint(res); 29 | 30 | console.log(res_bigint); 31 | }); 32 | 33 | // Try to test it for the bn254 field 34 | // 1 + p = 1 35 | it('testing ForeignField.add() for bn254 prime', function() { 36 | let pbn254 = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; 37 | 38 | let x = Field3.from(1n); 39 | let y = Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208583n); 40 | 41 | let res = ForeignField.add(x, y, pbn254); 42 | let res_bigint = Field3.toBigint(res); 43 | 44 | assert(res_bigint == 1n); 45 | }); 46 | 47 | // Try to test it for the bn254 field 48 | // 1 + (p - 1) = 0 49 | it('testing ForeignField.add() for bn254 prime', function() { 50 | let pbn254 = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; 51 | 52 | let x = Field3.from(1n); 53 | let y = Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208582n); 54 | 55 | let res = ForeignField.add(x, y, pbn254); 56 | let res_bigint = Field3.toBigint(res); 57 | 58 | assert(res_bigint == 0n); 59 | }); 60 | 61 | // 3n * 3n == 2n mod 7n 62 | it('testing ForeignField.mul', function() { 63 | let a = Field3.from(3n); 64 | let b = Field3.from(3n); 65 | let p = 7n; 66 | 67 | let res = ForeignField.mul(a, b, p); 68 | let res_bigint = Field3.toBigint(res); 69 | 70 | assert(res_bigint == 2n); 71 | }); 72 | 73 | 74 | }); -------------------------------------------------------------------------------- /src/g1.test.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | import { assert } from 'o1js/dist/node/lib/errors'; 3 | import G1Group from './g1'; 4 | 5 | 6 | describe('test bn254 g1', function() { 7 | 8 | // O + O = O 9 | it('Add bn254', function() { 10 | console.log("Add two bn254 group element"); 11 | let x = new G1Group(new PrimeField(0n), new PrimeField(0n)); 12 | let y = new G1Group(new PrimeField(0n), new PrimeField(0n)); 13 | 14 | let p = x.add(y); 15 | p.assertEquals(G1Group.zero()); 16 | 17 | }); 18 | 19 | // O + G = G 20 | it('Add bn254 v2', function() { 21 | console.log("Add zero and the generator"); 22 | //let p = G1Group.generator().add(G1Group.zero()); 23 | let p = G1Group.generator(); 24 | p = p.add(G1Group.zero()); 25 | console.log(p); 26 | console.log(G1Group.zero()); 27 | p.assertEquals(G1Group.generator()); 28 | console.log(p); 29 | }); 30 | 31 | // 2*G + G = 3G 32 | it('Add bn254 v3', function() { 33 | console.log("Test 2 * G + G = 3 * G"); 34 | let p = G1Group.generator().double(); 35 | let q = G1Group.generator(); 36 | 37 | let g3 = p.add(q); 38 | g3.assertEquals(G1Group.g_3()); 39 | }); 40 | 41 | // (2*G + G) + G = 4*G 42 | //it('Add bn254 v3', function() { 43 | // console.log("Add 3 * generator and the generator"); 44 | // //let p = G1Group.generator.add(G1Group.generator.double()); 45 | // //let q = G1Group.generator.double().add(G1Group.generator.double()); 46 | // //let p_add_1 = p.add(G1Group.generator); 47 | // //p_add_1.assertEquals(q); 48 | // 49 | // console.log("Double generator is:"); 50 | // let p = G1Group.generator().double(); 51 | // console.log(p); 52 | // console.log("p3 is"); 53 | // let p_3 = p.add(G1Group.generator()); 54 | // console.log(p_3); 55 | // let p_4 = p_3.add(G1Group.generator()); 56 | // 57 | // let g_4 = p.add(p); 58 | // console.log(p_4); 59 | // console.log(g_4); 60 | // //p_4.assertEquals(g_4); 61 | //}); 62 | 63 | //it('Add bn254 v4', function() { 64 | // console.log("Add 4 * generator and the generator"); 65 | // 66 | // console.log("Double generator is:"); 67 | // let p_2 = G1Group.generator().add(G1Group.generator()); 68 | // let p_3 = p_2.add(G1Group.generator()); 69 | // let p_4 = p_3.add(G1Group.generator()); 70 | // 71 | // let q_2 = G1Group.generator().double(); 72 | // let q_4 = q_2.double(); 73 | // 74 | // console.log("Generate p_4"); 75 | // console.log(p_4); 76 | // 77 | // console.log("Generate q_4"); 78 | // console.log(q_4); 79 | // 80 | // console.log("Generate g_4"); 81 | // console.log(G1Group.g_4()); 82 | //}); 83 | }); -------------------------------------------------------------------------------- /src/primeField.test.ts: -------------------------------------------------------------------------------- 1 | import {Field, Poseidon, Group} from 'o1js'; 2 | import { isConstructorDeclaration } from 'typescript'; 3 | import Fp2 from './fp2'; 4 | import PrimeField from './primeField'; 5 | import { UInt64 } from 'o1js/dist/node/provable/field-bigint'; 6 | 7 | 8 | describe('test PrimeField', function() { 9 | //it('test noble curve field', function() { 10 | // console.log("Testing the noble Field."); 11 | // let a = nonField(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')); 12 | // console.log(a); 13 | // console.log("Print bigint") 14 | // console.log(BigInt(28948022309329048855892746252171976963317496166410141009864396001978282409984)); 15 | // let b = nonField(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')); 16 | // console.log(b); 17 | // let c = nonField(BigInt(234234)); 18 | // let d = c.mulN(6n, 4n); 19 | // console.log(11%5); 20 | //}); 21 | 22 | //it('test PrimeField add', function() { 23 | // let x = new PrimeField(1n); 24 | // let y = new PrimeField(21888242871839275222246405745257275088696311157297823662689037894645226208583n); 25 | // let z = x.add(y); 26 | // console.log(z); 27 | //}); 28 | 29 | it('new field element montgomery', function() { 30 | let x = new PrimeField(2n); 31 | let y = new PrimeField(1n); 32 | let mont_x = x.mul(new PrimeField(6350874878119819312338956282401532409788428879151445726012394534686998597021n)); 33 | let mont_y = y.mul(new PrimeField(6350874878119819312338956282401532409788428879151445726012394534686998597021n)); 34 | 35 | console.log(mont_x); 36 | console.log(mont_y); 37 | }); 38 | 39 | //it('test PrimeField exp', function() { 40 | // let x = new PrimeField(1n); 41 | // let y = new PrimeField(21888242871839275222246405745257275088696311157297823662689037894645226208583n); 42 | // let z = x.exp(y); 43 | // console.log(z); 44 | // 45 | // let base = new PrimeField(2n); 46 | // let exponent = new PrimeField(3n); 47 | // let res = base.exp(exponent); 48 | // console.log(res); 49 | //}); 50 | // 51 | //it('test assertEquals', function() { 52 | // let x = new PrimeField(1n); 53 | // let y = new PrimeField(1n); 54 | // 55 | // x.assertEquals(y); 56 | //}); 57 | // 58 | //it('test inv and div', function() { 59 | // let x = new PrimeField(3451234123523542345345n); 60 | // let y = x.inv(); 61 | // 62 | // let res = x.mul(y); 63 | // 64 | // let res_z = x.div(x); 65 | // console.log(res_z); 66 | // console.log(res); 67 | // //x.assertEquals(y); 68 | //}); 69 | // 70 | // 71 | //it('test neg', function() { 72 | // console.log("testing neg"); 73 | // let x = new PrimeField(3451234123523542345345n); 74 | // let y = x.neg(); 75 | // let sum = x.add(y); 76 | // console.log(sum); 77 | // //x.assertEquals(y); 78 | //}); 79 | }); -------------------------------------------------------------------------------- /src/g1_new.test.ts: -------------------------------------------------------------------------------- 1 | import Fq from './fq'; 2 | import G1 from './g1_new'; 3 | 4 | 5 | describe('test G1 for BN254', function() { 6 | //G + G in projective coordinates is: 7 | //x 8 | //21888242871839275222246405745257275088696311157297823662689037894645226208491 9 | //y 10 | //21888242871839275222246405745257275088696311157297823662689037894645226208572 11 | //z 12 | //64 13 | 14 | it('add G1 example 1 comparison', function() { 15 | console.log("Add two generators"); 16 | let generator = G1.generator(); 17 | let res = generator.add(generator); 18 | 19 | console.log(res.x.toBigInt()); 20 | console.log(res.y.toBigInt()); 21 | console.log(res.z.toBigInt()); 22 | }); 23 | 24 | //2G + G in projective coordinates is: 25 | //x 26 | //146094 27 | //y 28 | //21888242871839275222246405745257275088696311157297823662689037894645225946843 29 | //z 30 | //118638 31 | 32 | it('add G1 example 2 comparison', function() { 33 | console.log("Add three generators"); 34 | let generator = G1.generator(); 35 | let res = generator.add(generator); 36 | res = res.add(generator); 37 | 38 | console.log(res.x.toBigInt()); 39 | console.log(res.y.toBigInt()); 40 | console.log(res.z.toBigInt()); 41 | }); 42 | 43 | //G + G in projective coordinates is: 44 | //x 45 | //21888242871839275222246405745257275088696311157297823662689037894645226208491 46 | //y 47 | //21888242871839275222246405745257275088696311157297823662689037894645226208572 48 | //z 49 | //64 50 | 51 | it('double G1 example 1 comparison', function() { 52 | console.log("Double the generator"); 53 | let generator = G1.generator(); 54 | let res = generator.double(); 55 | 56 | console.log(res.x.toBigInt()); 57 | console.log(res.y.toBigInt()); 58 | console.log(res.z.toBigInt()); 59 | }); 60 | 61 | //3G + G in projective coordinates is: 62 | //x 63 | //9838105376 64 | //y 65 | //178203765652 66 | //z 67 | //29984768 68 | 69 | // 70 | it('double G1 example 2 comparison', function() { 71 | console.log("3*G + G = 2*(2*G) Affine Repr Check"); 72 | let generator = G1.generator(); 73 | let res = generator.double(); 74 | res = res.double(); 75 | 76 | console.log(res.x.toBigInt()); 77 | console.log(res.y.toBigInt()); 78 | console.log(res.z.toBigInt()); 79 | 80 | let g_3_1_jacob = new G1( 81 | new Fq(9838105376n), 82 | new Fq(178203765652n), 83 | new Fq(29984768n) 84 | ) 85 | 86 | let res_affine = res.to_affine(); 87 | let g_3_1_jacob_affine = g_3_1_jacob.to_affine(); 88 | 89 | console.log(res_affine.x.toBigInt()); 90 | console.log(res_affine.y.toBigInt()); 91 | //console.log(res_affine.z.toBigInt()); 92 | 93 | console.log(g_3_1_jacob_affine.x.toBigInt()); 94 | console.log(g_3_1_jacob_affine.y.toBigInt()); 95 | //console.log(g_3_1_jacob_affine.z.toBigInt()); 96 | }); 97 | 98 | }); -------------------------------------------------------------------------------- /src/fq_provable.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'o1js/dist/node/lib/errors'; 2 | import Fq from './fq_provable'; 3 | import { ForeignField, Field3} from 'o1js/dist/node/lib/gadgets/foreign-field'; 4 | import { Field } from 'o1js'; 5 | 6 | 7 | describe('test Fq bn254', function() { 8 | // 1 + p = 1 mod p 9 | it('add Fq example 1', function() { 10 | console.log("Construct a new Fq Test 1 + p == 1 mod p"); 11 | let x = new Fq(Field3.from(1n)); 12 | let y = new Fq(Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208583n)); 13 | 14 | let res = x.add(y); 15 | let res_bigint = res.toBigInt(); 16 | 17 | assert(res_bigint == 1n); 18 | }); 19 | 20 | // 1 + (p - 1) == 0 mod p 21 | it('add Fq example 2', function() { 22 | console.log("Construct a new Fq Test 1 + (p - 1) == 0 mod p"); 23 | let x = new Fq(Field3.from(1n)); 24 | let y = new Fq(Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208582n)); 25 | 26 | let res = x.add(y); 27 | let res_bigint = res.toBigInt(); 28 | 29 | assert(res_bigint == 0n); 30 | 31 | }); 32 | 33 | // 1 - p == 1 mod p 34 | it('sub Fq example 1', function() { 35 | console.log("Construct a new Fq Test 1 + (p - 1) == 0 mod p"); 36 | let x = new Fq(Field3.from(1n)); 37 | let y = new Fq(Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208583n)); 38 | 39 | let res = x.sub(y); 40 | let res_bigint = res.toBigInt(); 41 | 42 | assert(res_bigint == 1n); 43 | 44 | }); 45 | 46 | it('Inverse Constant Montgomery Form', function() { 47 | console.log("Print Inverse Constant"); 48 | console.log(0x87d20782e4866389); 49 | }); 50 | 51 | it('Paralel test using Halo2Curves', function() { 52 | console.log("Multiply root of unities") 53 | let x = new Fq(Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208582n)); 54 | let y = new Fq(Field3.from(21888242871839275222246405745257275088696311157297823662689037894645226208582n)); 55 | 56 | let res = x.mul(y); 57 | let res_bigint = res.toBigInt(); 58 | 59 | console.log(res_bigint); 60 | }); 61 | 62 | // a + (b + c) == a + (c + b) == b + (c + a) 63 | it('Add Fq2', function() { 64 | console.log("Add two Fq2"); 65 | 66 | }); 67 | 68 | // a * (b * c) == a * (c * b) = b * (c * a) 69 | it('Mul Fq2', function() { 70 | console.log("Mul two Fq2"); 71 | 72 | }); 73 | 74 | // a + a == 2*a 75 | it('Square Fq2', function() { 76 | 77 | }); 78 | 79 | // a*a^-1 == O 80 | // Here, we test for the Pallas Curve 81 | // Change it to BN254 later by using the following 82 | // let a = new Fq2(new PrimeField(1), new PrimeField(2)); 83 | // We will try this invert now 84 | it('Invert Fq2', function() { 85 | 86 | }); 87 | 88 | // (2+2u) * (9+u) = (16+20u) 89 | it('Mul By Nonresidue Fq2', function() { 90 | 91 | }); 92 | }); -------------------------------------------------------------------------------- /src/fq.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'o1js/dist/node/lib/errors'; 2 | import Fq from './fq'; 3 | import { ForeignField, Field3} from 'o1js/dist/node/lib/gadgets/foreign-field'; 4 | 5 | 6 | describe('test Fq bn254', function() { 7 | // 1 + p = 1 mod p 8 | it('add Fq example 1', function() { 9 | console.log("Construct a new Fq Test 1 + p == 1 mod p"); 10 | let x = new Fq(1n); 11 | let y = new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208583n); 12 | 13 | let res = x.add(y); 14 | let res_bigint = res.toBigInt(); 15 | 16 | assert(res_bigint == 1n); 17 | }); 18 | 19 | // 1 + (p - 1) == 0 mod p 20 | it('add Fq example 2', function() { 21 | console.log("Construct a new Fq Test 1 + (p - 1) == 0 mod p"); 22 | let x = new Fq(1n); 23 | let y = new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n); 24 | 25 | let res = x.add(y); 26 | let res_bigint = res.toBigInt(); 27 | 28 | assert(res_bigint == 0n); 29 | 30 | }); 31 | 32 | // 1 - p == 1 mod p 33 | it('sub Fq example 1', function() { 34 | console.log("Construct a new Fq Test 1 + (p - 1) == 0 mod p"); 35 | let x = new Fq(1n); 36 | let y = new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208583n); 37 | 38 | let res = x.sub(y); 39 | let res_bigint = res.toBigInt(); 40 | 41 | assert(res_bigint == 1n); 42 | 43 | }); 44 | 45 | it('Inverse Constant Montgomery Form', function() { 46 | console.log("Print Inverse Constant"); 47 | console.log(0x87d20782e4866389); 48 | }); 49 | 50 | it('Paralel test using Halo2Curves', function() { 51 | console.log("Multiply root of unities") 52 | let x = new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n); 53 | let y = new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n); 54 | 55 | let res = x.mul(y); 56 | let res_bigint = res.toBigInt(); 57 | 58 | console.log(res_bigint); 59 | }); 60 | 61 | // a + (b + c) == a + (c + b) == b + (c + a) 62 | it('Add Fq2', function() { 63 | console.log("Add two Fq2"); 64 | 65 | }); 66 | 67 | // a * (b * c) == a * (c * b) = b * (c * a) 68 | it('Mul Fq2', function() { 69 | console.log("Mul two Fq2"); 70 | 71 | }); 72 | 73 | // a + a == 2*a 74 | it('Square Fq2', function() { 75 | 76 | }); 77 | 78 | // a*a^-1 == O 79 | // Here, we test for the Pallas Curve 80 | // Change it to BN254 later by using the following 81 | // let a = new Fq2(new PrimeField(1), new PrimeField(2)); 82 | // We will try this invert now 83 | it('Invert Fq2', function() { 84 | 85 | }); 86 | 87 | // (2+2u) * (9+u) = (16+20u) 88 | it('Mul By Nonresidue Fq2', function() { 89 | 90 | }); 91 | 92 | it('Calculate R^-1', function() { 93 | let x = Fq.R(); 94 | let y = x.inv(); 95 | console.log(y.toBigInt()); 96 | 97 | console.log(Fq.R().mul(Fq.R_INV_TEMP()).toBigInt()); 98 | }); 99 | 100 | 101 | }); -------------------------------------------------------------------------------- /src/interact.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This script can be used to interact with the Add contract, after deploying it. 3 | * 4 | * We call the update() method on the contract, create a proof and send it to the chain. 5 | * The endpoint that we interact with is read from your config.json. 6 | * 7 | * This simulates a user interacting with the zkApp from a browser, except that here, sending the transaction happens 8 | * from the script and we're using your pre-funded zkApp account to pay the transaction fee. In a real web app, the user's wallet 9 | * would send the transaction and pay the fee. 10 | * 11 | * To run locally: 12 | * Build the project: `$ npm run build` 13 | * Run with node: `$ node build/src/interact.js `. 14 | */ 15 | import { Mina, PrivateKey } from 'o1js'; 16 | import fs from 'fs/promises'; 17 | import { Add } from './Add.js'; 18 | 19 | // check command line arg 20 | let deployAlias = process.argv[2]; 21 | if (!deployAlias) 22 | throw Error(`Missing argument. 23 | 24 | Usage: 25 | node build/src/interact.js 26 | `); 27 | Error.stackTraceLimit = 1000; 28 | 29 | // parse config and private key from file 30 | type Config = { 31 | deployAliases: Record< 32 | string, 33 | { 34 | url: string; 35 | keyPath: string; 36 | fee: string; 37 | feepayerKeyPath: string; 38 | feepayerAlias: string; 39 | } 40 | >; 41 | }; 42 | let configJson: Config = JSON.parse(await fs.readFile('config.json', 'utf8')); 43 | let config = configJson.deployAliases[deployAlias]; 44 | let feepayerKeysBase58: { privateKey: string; publicKey: string } = JSON.parse( 45 | await fs.readFile(config.feepayerKeyPath, 'utf8') 46 | ); 47 | 48 | let zkAppKeysBase58: { privateKey: string; publicKey: string } = JSON.parse( 49 | await fs.readFile(config.keyPath, 'utf8') 50 | ); 51 | 52 | let feepayerKey = PrivateKey.fromBase58(feepayerKeysBase58.privateKey); 53 | let zkAppKey = PrivateKey.fromBase58(zkAppKeysBase58.privateKey); 54 | 55 | // set up Mina instance and contract we interact with 56 | const Network = Mina.Network(config.url); 57 | const fee = Number(config.fee) * 1e9; // in nanomina (1 billion = 1.0 mina) 58 | Mina.setActiveInstance(Network); 59 | let feepayerAddress = feepayerKey.toPublicKey(); 60 | let zkAppAddress = zkAppKey.toPublicKey(); 61 | let zkApp = new Add(zkAppAddress); 62 | 63 | let sentTx; 64 | // compile the contract to create prover keys 65 | console.log('compile the contract...'); 66 | await Add.compile(); 67 | try { 68 | // call update() and send transaction 69 | console.log('build transaction and create proof...'); 70 | let tx = await Mina.transaction({ sender: feepayerAddress, fee }, () => { 71 | zkApp.update(); 72 | }); 73 | await tx.prove(); 74 | console.log('send transaction...'); 75 | sentTx = await tx.sign([feepayerKey]).send(); 76 | } catch (err) { 77 | console.log(err); 78 | } 79 | if (sentTx?.hash() !== undefined) { 80 | console.log(` 81 | Success! Update transaction sent. 82 | 83 | Your smart contract state will be updated 84 | as soon as the transaction is included in a block: 85 | https://berkeley.minaexplorer.com/transaction/${sentTx.hash()} 86 | `); 87 | } 88 | -------------------------------------------------------------------------------- /src/fp12.test.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | import Fp2 from './fp2'; 3 | import Fp6 from './fp6'; 4 | import Fp12 from './fp12'; 5 | import { assert } from 'o1js/dist/node/lib/errors'; 6 | 7 | 8 | describe('test fp12', function() { 9 | 10 | // a + (b + c) == a + (c + b) == b + (c + a) 11 | it('Add Fp12', function() { 12 | console.log("Add three Fp12"); 13 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 14 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 15 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 16 | 17 | let x1 = new Fp6(x, y, z); 18 | let x2 = new Fp6(x, x, y); 19 | let x3 = new Fp6(y, z, z); 20 | let x4 = new Fp6(z, y, x); 21 | 22 | let a1 = new Fp12(x1, x4); 23 | let a2 = new Fp12(x3, x2); 24 | let a3 = new Fp12(x4, x2); 25 | 26 | let t0 = a1.add(a2.add(a3)); 27 | let t1 = a1.add(a3.add(a2)); 28 | let t2 = a2.add(a3.add(a1)); 29 | 30 | t0.assertEquals(t1); 31 | t0.assertEquals(t2); 32 | t1.assertEquals(t2); 33 | }); 34 | 35 | // a * (b * c) == a * (c * b) = b * (c * a) 36 | it('Mul Fp12', function() { 37 | console.log("Mul three Fp12"); 38 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 39 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 40 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 41 | 42 | let x1 = new Fp6(x, y, z); 43 | let x2 = new Fp6(x, x, y); 44 | let x3 = new Fp6(y, z, z); 45 | let x4 = new Fp6(z, y, x); 46 | 47 | let a1 = new Fp12(x1, x4); 48 | let a2 = new Fp12(x3, x2); 49 | let a3 = new Fp12(x4, x2); 50 | 51 | let t0 = a1.mul(a2.mul(a3)); 52 | let t1 = a1.mul(a3.mul(a2)); 53 | let t2 = a2.mul(a3.mul(a1)); 54 | 55 | t0.assertEquals(t1); 56 | t0.assertEquals(t2); 57 | t1.assertEquals(t2); 58 | }); 59 | 60 | // a * a == 2*a 61 | it('Square Fp12', function() { 62 | console.log("Square one Fp12"); 63 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 64 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 65 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 66 | 67 | let x1 = new Fp6(x, y, z); 68 | let x2 = new Fp6(x, x, y); 69 | let x3 = new Fp6(y, z, z); 70 | let x4 = new Fp6(z, y, x); 71 | 72 | let a = new Fp12(x1, x4); 73 | let b = a.mul(a); 74 | let c = a.square(); 75 | 76 | b.assertEquals(c); 77 | }); 78 | 79 | 80 | it('Invert Fp12', function() { 81 | console.log("Invert an element in Fp12"); 82 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 83 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 84 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 85 | 86 | let x1 = new Fp6(x, y, z); 87 | let x2 = new Fp6(x, x, y); 88 | let x3 = new Fp6(y, z, z); 89 | let x4 = new Fp6(z, y, x); 90 | 91 | let a = new Fp12(x1, x3); 92 | let d = new Fp12(x2, x4); 93 | 94 | let b = a.invert(); 95 | let c = a.mul(b); 96 | 97 | c.isOne(); 98 | }); 99 | 100 | }); -------------------------------------------------------------------------------- /src/fp2.test.ts: -------------------------------------------------------------------------------- 1 | import {Field, Poseidon, Group} from 'o1js'; 2 | import { isConstructorDeclaration } from 'typescript'; 3 | import Fp2 from './fp2'; 4 | import PrimeField from './primeField'; 5 | 6 | 7 | describe('test fp2', function() { 8 | it('new', function() { 9 | console.log("Construct a new Fp2"); 10 | let x_fp2 = new Fp2(new PrimeField(20n), new PrimeField(10n)); 11 | console.log(x_fp2.c0); 12 | console.log(x_fp2.c1); 13 | 14 | console.log("Construct a zero Fp2"); 15 | let zero = new Fp2(new PrimeField(0n), new PrimeField(0n)); 16 | console.log(zero.c0); 17 | console.log(zero.c1); 18 | }); 19 | 20 | it('Add Fp2 example', function() { 21 | console.log("Add two Fp2"); 22 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 23 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 24 | let sum = x.add(y); 25 | console.log(sum.c0); 26 | console.log(sum.c1); 27 | 28 | sum.c0.assertEquals(new PrimeField(32n)); 29 | sum.c1.assertEquals(new PrimeField(25n)); 30 | }); 31 | 32 | // a + (b + c) == a + (c + b) == b + (c + a) 33 | it('Add Fp2', function() { 34 | console.log("Add two Fp2"); 35 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 36 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 37 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 38 | 39 | let t0 = x.add(y.add(z)); 40 | let t1 = x.add(z.add(y)); 41 | let t2 = y.add(z.add(x)); 42 | 43 | t0.c0.assertEquals(t1.c0); 44 | t0.c0.assertEquals(t2.c0); 45 | t1.c0.assertEquals(t2.c0); 46 | t0.c1.assertEquals(t1.c1); 47 | t0.c1.assertEquals(t2.c1); 48 | t1.c1.assertEquals(t2.c1); 49 | }); 50 | 51 | // a * (b * c) == a * (c * b) = b * (c * a) 52 | it('Mul Fp2', function() { 53 | console.log("Mul two Fp2"); 54 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 55 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 56 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 57 | 58 | let t0 = x.mul(y.mul(z)); 59 | let t1 = x.mul(z.mul(y)); 60 | let t2 = y.mul(z.mul(x)); 61 | 62 | t0.c0.assertEquals(t1.c0); 63 | t0.c0.assertEquals(t2.c0); 64 | t1.c0.assertEquals(t2.c0); 65 | t0.c1.assertEquals(t1.c1); 66 | t0.c1.assertEquals(t2.c1); 67 | t1.c1.assertEquals(t2.c1); 68 | }); 69 | 70 | // a + a == 2*a 71 | it('Square Fp2', function() { 72 | console.log("Square one Fp2"); 73 | let a = new Fp2(new PrimeField(20n), new PrimeField(10n)); 74 | let b = a.mul(a); 75 | let c = a.square(); 76 | 77 | b.c0.assertEquals(c.c0); 78 | b.c1.assertEquals(c.c1); 79 | }); 80 | 81 | // a*a^-1 == O 82 | // Here, we test for the Pallas Curve 83 | // Change it to BN254 later by using the following 84 | // let a = new Fp2(new PrimeField(1), new PrimeField(2)); 85 | // We will try this invert now 86 | it('Invert Fp2', function() { 87 | console.log("Invert the generator of BN254"); 88 | 89 | let a = new Fp2(new PrimeField(1n), new PrimeField(2n)); 90 | let b = a.invert(); 91 | let c = a.mul(b); 92 | 93 | c.isOne() 94 | }); 95 | 96 | // (2+2u) * (9+u) = (16+20u) 97 | it('Mul By Nonresidue Fp2', function() { 98 | console.log("Invert the generator of BN254"); 99 | 100 | let a = new Fp2(new PrimeField(2n), new PrimeField(2n)); 101 | a = a.mul_by_nonresidue(); 102 | 103 | console.log(a); 104 | }); 105 | }); -------------------------------------------------------------------------------- /src/primeField.ts: -------------------------------------------------------------------------------- 1 | import assert from "o1js/dist/node/lib/errors"; 2 | 3 | export default class PrimeField{ 4 | modulus: bigint; 5 | value: bigint; 6 | 7 | constructor(value: bigint) { 8 | this.modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; 9 | this.value = this.mod(value); 10 | } 11 | 12 | static INV() { 13 | return new PrimeField(9786893198990664585n); 14 | } 15 | 16 | mod(value: bigint): bigint { 17 | return value >= 0n 18 | ? value % this.modulus 19 | : ((value % this.modulus) + this.modulus) % this.modulus; 20 | } 21 | 22 | add(x: PrimeField) { 23 | return new PrimeField(this.mod(this.value + x.value)); 24 | } 25 | 26 | sub(x: PrimeField) { 27 | return new PrimeField(this.mod(this.value - x.value)); 28 | } 29 | 30 | mul(x: PrimeField) { 31 | return new PrimeField(this.mod(this.value * x.value)); 32 | } 33 | 34 | div(x: PrimeField) { 35 | return new PrimeField(this.mod(this.mul(x.inv()).value)); 36 | } 37 | 38 | // this * this = this^2 39 | square() { 40 | return new PrimeField(this.mul(this).value); 41 | } 42 | 43 | // this + this = 2 * this 44 | double() { 45 | return new PrimeField(this.add(this).value); 46 | } 47 | 48 | inv() { 49 | let low = this.mod(this.value); 50 | if (low === 0n) return new PrimeField(0n); 51 | let lm = 1n, hm = 0n; 52 | let high = this.modulus; 53 | 54 | while (low > 1n) { 55 | let r = high / low; 56 | let nm = hm - lm * r; 57 | let nw = high - low * r; 58 | 59 | high = low; 60 | hm = lm; 61 | lm = nm; 62 | low = nw; 63 | } 64 | return new PrimeField(this.mod(lm)); 65 | } 66 | 67 | neg() { 68 | return new PrimeField(this.mod(0n - this.value)); 69 | } 70 | 71 | exp(exponent: PrimeField) { 72 | let base = new PrimeField(this.mod(this.value)); 73 | 74 | if (base.value === 0n) { 75 | if (exponent.value === 0n) { 76 | throw new TypeError('Base and exponent cannot be both 0'); 77 | } 78 | return new PrimeField(0n); 79 | } 80 | 81 | // handle raising to negative power 82 | if (exponent.value < 0n) { 83 | base = base.inv(); 84 | exponent = exponent.neg(); 85 | } 86 | 87 | let result = new PrimeField(1n); 88 | while (exponent.value > 0n) { 89 | if (exponent.value % 2n) { 90 | result = result.mul(base); 91 | } 92 | exponent = new PrimeField(exponent.value / 2n); 93 | base = base.mul(base); 94 | } 95 | 96 | return result; 97 | } 98 | 99 | assertEquals(x: PrimeField, message?: string) { 100 | try { 101 | if (this.value !== x.value) { 102 | throw Error(`Field.assertEquals(): ${this.value} != ${x.value}`); 103 | } 104 | return; 105 | } catch (err) { 106 | throw this.withMessage(err, message); 107 | 108 | } 109 | } 110 | 111 | withMessage(error: unknown, message?: string) { 112 | if (message === undefined || !(error instanceof Error)) return error; 113 | error.message = `${message}\n${error.message}`; 114 | return error; 115 | } 116 | 117 | equals(x: PrimeField) { 118 | if (this.value === x.value) { 119 | return true; 120 | } else { 121 | return false; 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /src/g1_new.ts: -------------------------------------------------------------------------------- 1 | import Fq from "./fq"; 2 | import G1Affine from "./g1_affine"; 3 | 4 | export default class G1{ 5 | x: Fq; 6 | y: Fq; 7 | z: Fq; 8 | 9 | constructor(x: Fq, y: Fq, z: Fq) { 10 | // we can add checks later 11 | this.x = x; 12 | this.y = y; 13 | this.z = z; 14 | } 15 | 16 | static a = new Fq(0n); 17 | static b = new Fq(3n); 18 | 19 | static generator() { 20 | return new G1( 21 | new Fq(1n), 22 | new Fq(2n), 23 | new Fq(1n) 24 | ); 25 | } 26 | 27 | static identity() { 28 | return new G1( 29 | new Fq(0n), 30 | new Fq(1n), 31 | new Fq(0n) 32 | ) 33 | } 34 | 35 | withMessage(error: unknown, message?: string) { 36 | if (message === undefined || !(error instanceof Error)) return error; 37 | error.message = `${message}\n${error.message}`; 38 | return error; 39 | } 40 | 41 | add(other: G1) { 42 | let t0 = this.x.mul(other.x); 43 | let t1 = this.y.mul(other.y); 44 | let t2 = this.z.mul(other.z); 45 | let t3 = this.x.add(this.y); 46 | let t4 = other.x.add(other.y); 47 | t3 = t3.mul(t4); 48 | t4 = t0.add(t1); 49 | t3 = t3.sub(t4); 50 | t4 = this.y.add(this.z); 51 | let x3 = other.y.add(other.z); 52 | t4 = t4.mul(x3); 53 | x3 = t1.add(t2); 54 | t4 = t4.sub(x3); 55 | x3 = this.x.add(this.z); 56 | let y3 = other.x.add(other.z); 57 | x3 = x3.mul(y3); 58 | y3 = t0.add(t2); 59 | y3 = x3.sub(y3); 60 | x3 = t0.add(t0); 61 | t0 = x3.add(t0); 62 | 63 | //t2 = t2.mul_by_3b(); 64 | let input = t2; 65 | t2 = t2.double(); 66 | t2 = t2.double(); 67 | t2 = t2.double(); 68 | t2 = t2.add(input); 69 | 70 | let z3 = t1.add(t2); 71 | t1 = t1.sub(t2); 72 | 73 | //y3 = y3.mul_by_3b(); 74 | input = y3; 75 | y3 = y3.double(); 76 | y3 = y3.double(); 77 | y3 = y3.double(); 78 | y3 = y3.add(input); 79 | 80 | x3 = t4.mul(y3); 81 | t2 = t3.mul(t1); 82 | x3 = t2.sub(x3); 83 | y3 = y3.mul(t0); 84 | t1 = t1.mul(z3); 85 | y3 = t1.add(y3); 86 | t0 = t0.mul(t3); 87 | z3 = z3.mul(t4); 88 | z3 = z3.add(t0); 89 | 90 | return new G1( 91 | x3, 92 | y3, 93 | z3 94 | ); 95 | } 96 | 97 | double() { 98 | let t0 = this.y.square(); 99 | let z3 = t0.add(t0); 100 | z3 = z3.add(z3); 101 | z3 = z3.add(z3); 102 | let t1 = this.y.mul(this.z); 103 | let t2 = this.z.square(); 104 | 105 | //t2 = t2.mul_by_3b(); 106 | let input = t2; 107 | t2 = t2.double(); 108 | t2 = t2.double(); 109 | t2 = t2.double(); 110 | t2 = t2.add(input); 111 | 112 | let x3 = t2.mul(z3); 113 | let y3 = t0.add(t2); 114 | z3 = t1.mul(z3); 115 | t1 = t2.add(t2); 116 | t2 = t1.add(t2); 117 | t0 = t0.sub(t2); 118 | y3 = t0.mul(y3); 119 | y3 = x3.add(y3); 120 | t1 = this.x.mul(this.y); 121 | x3 = t0.mul(t1); 122 | x3 = x3.add(x3); 123 | 124 | return new G1( 125 | x3, 126 | y3, 127 | z3 128 | ); 129 | } 130 | 131 | to_affine() { 132 | let z_inv = this.z.inv(); 133 | let x = this.x.mul(z_inv); 134 | let y = this.y.mul(z_inv); 135 | 136 | // conditional_select?? 137 | 138 | // As an affine, let's have z = 0 with G1 139 | return new G1Affine( 140 | x, 141 | y, 142 | ) 143 | } 144 | 145 | } -------------------------------------------------------------------------------- /src/fp6.test.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | import Fp2 from './fp2'; 3 | import Fp6 from './fp6'; 4 | 5 | 6 | describe('test fp6', function() { 7 | it('new', function() { 8 | console.log("Construct a new Fp6"); 9 | 10 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 11 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 12 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 13 | 14 | let x1 = new Fp6(x, y, z); 15 | let x2 = new Fp6(x, x, y); 16 | let x3 = new Fp6(y, z, z); 17 | 18 | console.log(x1.c0.c0); 19 | console.log(x1.c0.c1); 20 | console.log(x1.c1.c0); 21 | console.log(x1.c1.c1); 22 | console.log(x1.c2.c0); 23 | console.log(x1.c2.c1); 24 | 25 | console.log("Construct a zero Fp6"); 26 | let zero_fp2 = new Fp2(new PrimeField(0n), new PrimeField(0n)); 27 | let zero_fp6 = new Fp6(zero_fp2, zero_fp2, zero_fp2); 28 | 29 | console.log(zero_fp6.c0.c0); 30 | console.log(zero_fp6.c0.c1); 31 | console.log(zero_fp6.c1.c0); 32 | console.log(zero_fp6.c1.c1); 33 | console.log(zero_fp6.c2.c0); 34 | console.log(zero_fp6.c2.c1); 35 | }); 36 | 37 | // a + (b + c) == a + (c + b) == b + (c + a) 38 | it('Add Fp6', function() { 39 | console.log("Add three Fp6"); 40 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 41 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 42 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 43 | 44 | let x1 = new Fp6(x, y, z); 45 | let x2 = new Fp6(x, x, y); 46 | let x3 = new Fp6(y, z, z); 47 | 48 | let t0 = x1.add(x2.add(x3)); 49 | let t1 = x1.add(x3.add(x2)); 50 | let t2 = x2.add(x3.add(x1)); 51 | 52 | t0.c0.assertEquals(t1.c0); 53 | t0.c0.assertEquals(t2.c0); 54 | t1.c0.assertEquals(t2.c0); 55 | t0.c1.assertEquals(t1.c1); 56 | t0.c1.assertEquals(t2.c1); 57 | t1.c1.assertEquals(t2.c1); 58 | t0.c2.assertEquals(t1.c2); 59 | t0.c2.assertEquals(t2.c2); 60 | t1.c2.assertEquals(t2.c2); 61 | }); 62 | 63 | // a * (b * c) == a * (c * b) = b * (c * a) 64 | it('Mul Fp6', function() { 65 | console.log("Mul three Fp6"); 66 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 67 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 68 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 69 | 70 | let x1 = new Fp6(x, y, z); 71 | let x2 = new Fp6(x, x, y); 72 | let x3 = new Fp6(y, z, z); 73 | 74 | let t0 = x1.mul(x2.mul(x3)); 75 | let t1 = x1.mul(x3.mul(x2)); 76 | let t2 = x2.mul(x3.mul(x1)); 77 | 78 | t0.c0.assertEquals(t1.c0); 79 | t0.c0.assertEquals(t2.c0); 80 | t1.c0.assertEquals(t2.c0); 81 | t0.c1.assertEquals(t1.c1); 82 | t0.c1.assertEquals(t2.c1); 83 | t1.c1.assertEquals(t2.c1); 84 | t0.c2.assertEquals(t1.c2); 85 | t0.c2.assertEquals(t2.c2); 86 | t1.c2.assertEquals(t2.c2); 87 | }); 88 | 89 | // a * a == 2*a 90 | it('Square Fp6', function() { 91 | console.log("Square one Fp6"); 92 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 93 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 94 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 95 | 96 | let x1 = new Fp6(x, y, z); 97 | 98 | let a = x1.mul(x1); 99 | let b = x1.square(); 100 | 101 | a.assertEquals(b); 102 | 103 | console.log(a); 104 | console.log(b); 105 | console.log(a.assertEquals(b)); 106 | 107 | }); 108 | 109 | 110 | it('Invert Fp6', function() { 111 | console.log("Invert an element in Fp6"); 112 | let x = new Fp2(new PrimeField(20n), new PrimeField(10n)); 113 | let y = new Fp2(new PrimeField(12n), new PrimeField(15n)); 114 | let z = new Fp2(new PrimeField(25n), new PrimeField(40n)); 115 | 116 | let a = new Fp6(x, y, z); 117 | let b = a.invert(); 118 | let c = a.mul(b); 119 | 120 | c.isOne(); 121 | }); 122 | 123 | }); -------------------------------------------------------------------------------- /src/pairing.test.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | import Fp12 from './fp12'; 3 | import Fp2 from './fp2'; 4 | import Fp6 from './fp6'; 5 | import G1Group from './g1'; 6 | import G2Group from './g2'; 7 | import Pairing from './pairing'; 8 | 9 | 10 | describe('test pairing functions', function() { 11 | it('Test final exponentiation', function() { 12 | console.log("test fp12.one()"); 13 | let res = Pairing.final_exponentiation_gnark(Fp12.one()); 14 | res.assertEquals(Fp12.one()); 15 | }); 16 | 17 | it('Test final exponentiation', function() { 18 | console.log("test fp12.one() + fp12.one()"); 19 | //let res = Pairing.final_exponentiation(Fp12.one().add(Fp12.one())); 20 | //let res = Pairing.final_exponentiation_2_gnark(Fp12.one().add(Fp12.one()).add(Fp12.one())); 21 | 22 | //let ress = Fp12.one().add(Fp12.one().add(Fp12.one())); 23 | //console.log(ress.c0); 24 | //console.log(ress.c1); 25 | //res.assertEquals(Fp12.one()); 26 | //let res = Pairing.final_exponentiation_2_gnark(ress); 27 | //console.log(res.c0); 28 | //console.log(res.c1); 29 | 30 | let val = new Fp12( 31 | new Fp6( 32 | new Fp2(new PrimeField(1n), new PrimeField(1n)), 33 | new Fp2(new PrimeField(1n), new PrimeField(1n)), 34 | new Fp2(new PrimeField(1n), new PrimeField(1n)) 35 | ), 36 | new Fp6( 37 | new Fp2(new PrimeField(1n), new PrimeField(0n)), 38 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 39 | new Fp2(new PrimeField(0n), new PrimeField(0n)) 40 | ) 41 | ) 42 | 43 | let res = Pairing.final_exponentiation_gnark(val); 44 | console.log(res.c0); 45 | console.log(res.c1); 46 | 47 | //console.log(val.c0); 48 | //console.log(val.c1); 49 | //let res1 = Pairing.final_exponentiation(val); 50 | //console.log("Res1 final exp"); 51 | //console.log(res1.c0); 52 | //console.log(res1.c1); 53 | 54 | //let res2 = Pairing.final_exponentiation_2_gnark(val); 55 | //console.log("Res2 final exp"); 56 | //console.log(res2.c0); 57 | //console.log(res2.c1); 58 | //let t = 2**62 - 2**54 + 2**44 59 | //console.log("THE TRACE T is:"); 60 | //console.log(t); 61 | //let t_another = 2**63 - 2**49 62 | //// 4965661367192848881 -> t is in garaga/gnark 63 | //// 4593689212103950300 -> t is in the optimal ate pairing 64 | //console.log("This is another t"); 65 | //console.log(t_another); 66 | }); 67 | 68 | // e(P, Q + R) = e(P, Q) * e(P, R) 69 | //it('Test pair function', function() { 70 | // console.log("ttest bilinearity"); 71 | // let g1 = G1Group.generator(); 72 | // let g2 = G2Group.generator(); 73 | // g2 = g2.double(); 74 | // let pair12 = Pairing.pair(g2, g1); 75 | // 76 | // let g3 = G1Group.generator(); 77 | // let g4 = G2Group.generator(); 78 | // g3 = g3.double(); 79 | // let pair21 = Pairing.pair(g4, g3); 80 | // 81 | // console.log(pair12.c0); 82 | // console.log(pair21.c0); 83 | // 84 | // console.log(pair12.c1); 85 | // console.log(pair21.c1); 86 | //}); 87 | // 88 | //it('Pairing test', function() { 89 | // console.log("test pairing"); 90 | // let res = Pairing.pair(G2Group.generator(), G1Group.generator()); 91 | // console.log("Result of the pairing test") 92 | // console.log(res.c0); 93 | // console.log(res.c1); 94 | //}); 95 | 96 | //(18443897754565973717256850119554731228214108935025491924036055734000366132575, 10734401203193558706037776473742910696504851986739882094082017010340198538454, 5985796159921227033560968606339653189163760772067273492369082490994528765680, 4093294155816392700623820137842432921872230622290337094591654151434545306688, 642121370160833232766181493494955044074321385528883791668868426879070103434, 4527449849947601357037044178952942489926487071653896435602814872334098625391, 3758435817766288188804561253838670030762970764366672594784247447067868088068, 18059168546148152671857026372711724379319778306792011146784665080987064164612, 14656606573936501743457633041048024656612227301473084805627390748872617280984, 17918828665069491344039743589118342552553375221610735811112289083834142789347, 19455424343576886430889849773367397946457449073528455097210946839000147698372, 7484542354754424633621663080190936924481536615300815203692506276894207018007) 97 | 98 | }); -------------------------------------------------------------------------------- /src/fq2.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Fq.ts uses {ForeignField, Field3} from {Gadgets} 3 | */ 4 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 5 | import Fq from "./fq"; 6 | 7 | /// An element of Fq2, represented by c0 + c1 * u; where u^2 = -1. 8 | 9 | export default class Fq2{ 10 | c0: Fq; 11 | c1: Fq; 12 | 13 | constructor(c0: Fq, c1: Fq) { 14 | this.c0 = c0; 15 | this.c1 = c1; 16 | } 17 | 18 | add(other: Fq2) { 19 | return new Fq2( 20 | this.c0.add(other.c0), 21 | this.c1.add(other.c1) 22 | ); 23 | } 24 | 25 | sub(other: Fq2) { 26 | return new Fq2( 27 | this.c0.sub(other.c0), 28 | this.c1.sub(other.c1) 29 | ); 30 | } 31 | 32 | mul(other: Fq2) { 33 | let t0 = this.c0.add(this.c1); 34 | let t1 = this.c0.mul(other.c0); 35 | let t2 = this.c1.mul(other.c1); 36 | 37 | let c0 = t1.sub(t2); 38 | let c1 = other.c0.add(other.c1); 39 | 40 | t1 = t1.add(t2); 41 | t0 = t0.mul(c1); 42 | c1 = t0.sub(t1); 43 | 44 | return new Fq2( 45 | c0, 46 | c1 47 | ); 48 | } 49 | 50 | // https://github.com/privacy-scaling-explorations/halo2curves/blob/526c07cbac8358f2f661e2f5d84de02d476897c8/src/bn256/fq2.rs#L241 51 | neg() { 52 | return new Fq2( 53 | this.c0.neg(), 54 | this.c1.neg() 55 | ); 56 | } 57 | 58 | conjugate() { 59 | return new Fq2( 60 | this.c0, 61 | this.c1.neg() 62 | ); 63 | } 64 | 65 | double() { 66 | return new Fq2( 67 | this.c0.double(), 68 | this.c1.double() 69 | ) 70 | } 71 | 72 | square() { 73 | let ab = this.c0.mul(this.c1); 74 | let c0c1 = this.c0.add(this.c1); 75 | let c0 = this.c1.neg(); 76 | c0 = c0.add(this.c0); 77 | c0 = c0.mul(c0c1); 78 | c0 = c0.sub(ab); 79 | 80 | return new Fq2( 81 | c0.add(ab), 82 | ab.double() 83 | ); 84 | } 85 | 86 | static frobenius_coeff_fq2_c1() { 87 | return new Fq2( 88 | new Fq(1n), 89 | new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n) 90 | ) 91 | } 92 | 93 | frobenius_map(power: bigint) { 94 | if (power %2n == 0n) { 95 | return new Fq2( 96 | this.c0, 97 | this.c1.mul(new Fq(1n)) 98 | ); 99 | } else { 100 | return new Fq2( 101 | this.c0, 102 | this.c1.mul(new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n)) 103 | ) 104 | } 105 | } 106 | 107 | mul_by_nonresidue() { 108 | let t0 = this.c0; 109 | let t1 = this.c1; 110 | 111 | let c0 = t0.double().double().double(); 112 | let c1 = t1.double().double().double(); 113 | 114 | c0 = c0.add(t0); 115 | c0 = c0.sub(t1); 116 | 117 | c1 = c1.add(t1); 118 | c1 = c1.add(t0); 119 | 120 | return new Fq2( 121 | c0, 122 | c1 123 | ); 124 | } 125 | 126 | invert() { 127 | let t1 = this.c1; 128 | t1 = t1.square(); 129 | 130 | let t0 = this.c0; 131 | t0 = t0.square(); 132 | 133 | t0 = t0.add(t1); 134 | 135 | let t = t0.inv(); 136 | 137 | let c0 = this.c0.mul(t); 138 | let c1 = this.c1.mul(t); 139 | 140 | c1 = c1.neg(); 141 | 142 | return new Fq2( 143 | c0, 144 | c1 145 | ); 146 | } 147 | 148 | norm() { 149 | let t0 = this.c0.square(); 150 | let t1 = this.c1.square(); 151 | return t0.add(t1); 152 | } 153 | 154 | // need test 155 | static one() { 156 | return new Fq2( 157 | Fq.one(), 158 | Fq.zero() 159 | ) 160 | } 161 | 162 | static zero() { 163 | return new Fq2( 164 | Fq.zero(), 165 | Fq.zero() 166 | ) 167 | } 168 | 169 | 170 | } 171 | 172 | -------------------------------------------------------------------------------- /src/fq.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Fq.ts uses {ForeignField, Field3} from {Gadgets} 3 | */ 4 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 5 | import { Provable, provable } from "o1js"; 6 | 7 | export default class Fq{ 8 | value: Field3; 9 | modulus: bigint; 10 | 11 | constructor(value: bigint) { 12 | this.modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; 13 | this.value = Field3.from(value); 14 | } 15 | 16 | add(x: Fq) { 17 | return new Fq( 18 | Field3.toBigint(ForeignField.add(this.value, x.value, this.modulus)) 19 | ); 20 | } 21 | 22 | toBigInt() { 23 | return Field3.toBigint(this.value); 24 | } 25 | 26 | sub(x: Fq) { 27 | return new Fq( 28 | Field3.toBigint(ForeignField.sub(this.value, x.value, this.modulus)) 29 | ); 30 | } 31 | 32 | mul(x: Fq) { 33 | return new Fq( 34 | Field3.toBigint(ForeignField.mul(this.value, x.value, this.modulus)) 35 | ); 36 | } 37 | 38 | static INV_CONST() { 39 | return new Fq( 40 | 9786893198990664000n 41 | ); 42 | } 43 | 44 | static R() { 45 | return new Fq( 46 | 6350874878119819312338956282401532409788428879151445726012394534686998597021n, 47 | ); 48 | } 49 | 50 | static R_INV_TEMP() { 51 | return new Fq( 52 | 20988524275117001072002809824448087578619730785600314334253784976379291040311n, 53 | ); 54 | } 55 | 56 | static R_INV_GPT() { 57 | return new Fq( 58 | 1314162783548850030710075498808357129191011388855789191592867893308385983439n, 59 | ); 60 | } 61 | 62 | 63 | 64 | static R2() { 65 | return new Fq( 66 | 3096616502983703923843567936837374451735540968419076528771170197431451843209n 67 | ); 68 | } 69 | 70 | static R3() { 71 | return new Fq( 72 | 14921786541159648185948152738563080959093619838510245177710943249661917737183n 73 | ) 74 | } 75 | 76 | static NEGATIVE_ONE() { 77 | return new Fq( 78 | 15537367993719455909907449462855742678907882278146377936676643359958227611562n 79 | ) 80 | } 81 | 82 | // We are not sure in here 83 | static one() { 84 | return Fq.R(); 85 | } 86 | 87 | static TWO_INV() { 88 | return new Fq( 89 | 10944121435919637611123202872628637544348155578648911831344518947322613104292n 90 | ) 91 | } 92 | 93 | static ROOT_OF_UNITY() { 94 | return new Fq( 95 | 21888242871839275222246405745257275088696311157297823662689037894645226208582n 96 | ); 97 | } 98 | 99 | static ROOT_OF_UNITY_INV() { 100 | return new Fq( 101 | 21888242871839275222246405745257275088696311157297823662689037894645226208582n 102 | ); 103 | } 104 | 105 | static MULTIPLICATIVE_GENERATOR() { 106 | return new Fq( 107 | 3n 108 | ); 109 | } 110 | 111 | static DELTA() { 112 | return new Fq( 113 | 9n 114 | ); 115 | } 116 | 117 | inv(){ 118 | return new Fq( 119 | Field3.toBigint(ForeignField.inv(this.value, this.modulus)) 120 | ); 121 | } 122 | 123 | double() { 124 | return new Fq( 125 | Field3.toBigint(this.add(this).value) 126 | ); 127 | } 128 | 129 | square() { 130 | return new Fq( 131 | Field3.toBigint(this.mul(this).value) 132 | ); 133 | } 134 | 135 | div(x: Fq) { 136 | return new Fq( 137 | Field3.toBigint(ForeignField.div(this.value, x.value, this.modulus)) 138 | ); 139 | } 140 | 141 | // need test for this 142 | 143 | /*neg() { 144 | return new Fq( 145 | Field3.toBigint(ForeignField.sub(Field3.from(0n), this.value, this.modulus)) 146 | ); 147 | }*/ 148 | neg() { 149 | return new Fq( 150 | Field3.toBigint(ForeignField.sub(Field3.from(this.modulus), this.value, this.modulus)) 151 | ) 152 | } 153 | 154 | static zero() { 155 | return new Fq( 156 | Field3.toBigint(Field3.from(0n)) 157 | ); 158 | } 159 | 160 | 161 | } 162 | 163 | -------------------------------------------------------------------------------- /src/fp_mont.ts: -------------------------------------------------------------------------------- 1 | import { zkAppProver } from "o1js/dist/node/lib/account_update"; 2 | import assert from "o1js/dist/node/lib/errors"; 3 | import { UInt64 } from 'o1js/dist/node/provable/field-bigint'; 4 | 5 | const Limbs = 4; 6 | const Bits = 254; 7 | const Bytes = 32; 8 | 9 | const q0 = UInt64(4332616871279656263n); 10 | const q1 = UInt64(10917124144477883021n); 11 | const q2 = UInt64(13281191951274694749n); 12 | const q3 = UInt64(3486998266802970665n); 13 | 14 | const qInvNeg = UInt64(9786893198990664585n) 15 | 16 | export default class Element{ 17 | q0: UInt64; 18 | q1: UInt64; 19 | q2: UInt64; 20 | q3: UInt64; 21 | 22 | constructor(_q0: UInt64, _q1: UInt64, _q2: UInt64, _q3: UInt64) { 23 | this.q0 = _q0; 24 | this.q1 = _q1; 25 | this.q2 = _q2; 26 | this.q3 = _q3; 27 | } 28 | 29 | static qElement() { 30 | return new Element(q0, q1, q2, q3); 31 | } 32 | 33 | /*mod(value: bigint): bigint { 34 | return value >= 0n 35 | ? value % this.modulus 36 | : ((value % this.modulus) + this.modulus) % this.modulus; 37 | } 38 | 39 | add(x: Element) { 40 | return new Element(this.mod(this.value + x.value)); 41 | } 42 | 43 | sub(x: Element) { 44 | return new Element(this.mod(this.value - x.value)); 45 | } 46 | 47 | mul(x: Element) { 48 | return new Element(this.mod(this.value * x.value)); 49 | } 50 | 51 | div(x: Element) { 52 | return new Element(this.mod(this.mul(x.inv()).value)); 53 | } 54 | 55 | // this * this = this^2 56 | square() { 57 | return new Element(this.mul(this).value); 58 | } 59 | 60 | // this + this = 2 * this 61 | double() { 62 | return new Element(this.add(this).value); 63 | } 64 | 65 | inv() { 66 | let low = this.mod(this.value); 67 | if (low === 0n) return new Element(0n); 68 | let lm = 1n, hm = 0n; 69 | let high = this.modulus; 70 | 71 | while (low > 1n) { 72 | let r = high / low; 73 | let nm = hm - lm * r; 74 | let nw = high - low * r; 75 | 76 | high = low; 77 | hm = lm; 78 | lm = nm; 79 | low = nw; 80 | } 81 | return new Element(this.mod(lm)); 82 | } 83 | 84 | neg() { 85 | return new Element(this.mod(0n - this.value)); 86 | } 87 | 88 | exp(exponent: Element) { 89 | let base = new Element(this.mod(this.value)); 90 | 91 | if (base.value === 0n) { 92 | if (exponent.value === 0n) { 93 | throw new TypeError('Base and exponent cannot be both 0'); 94 | } 95 | return new Element(0n); 96 | } 97 | 98 | // handle raising to negative power 99 | if (exponent.value < 0n) { 100 | base = base.inv(); 101 | exponent = exponent.neg(); 102 | } 103 | 104 | let result = new Element(1n); 105 | while (exponent.value > 0n) { 106 | if (exponent.value % 2n) { 107 | result = result.mul(base); 108 | } 109 | exponent = new Element(exponent.value / 2n); 110 | base = base.mul(base); 111 | } 112 | 113 | return result; 114 | } 115 | 116 | assertEquals(x: Element, message?: string) { 117 | try { 118 | if (this.value !== x.value) { 119 | throw Error(`Field.assertEquals(): ${this.value} != ${x.value}`); 120 | } 121 | return; 122 | } catch (err) { 123 | throw this.withMessage(err, message); 124 | 125 | } 126 | } 127 | 128 | withMessage(error: unknown, message?: string) { 129 | if (message === undefined || !(error instanceof Error)) return error; 130 | error.message = `${message}\n${error.message}`; 131 | return error; 132 | } 133 | 134 | equals(x: Element) { 135 | if (this.value === x.value) { 136 | return true; 137 | } else { 138 | return false; 139 | } 140 | }*/ 141 | 142 | static rSquare() { 143 | return new Element( 144 | UInt64(17522657719365597833), 145 | UInt64(13107472804851548667), 146 | UInt64(5164255478447964150), 147 | UInt64(493319470278259999) 148 | ) 149 | } 150 | 151 | static newElement(v: UInt64) { 152 | 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /src/g1.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | 3 | export default class G1Group{ 4 | x: PrimeField; 5 | y: PrimeField; 6 | 7 | constructor(x: PrimeField, y: PrimeField) { 8 | // we can add checks later 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | static a = new PrimeField(0n); 14 | static b = new PrimeField(3n); 15 | 16 | static generator() { 17 | return new G1Group( 18 | new PrimeField(1n), 19 | new PrimeField(2n) 20 | ); 21 | } 22 | 23 | static g_4() { 24 | return new G1Group( 25 | new PrimeField(3010198690406615200373504922352659861758983907867017329644089018310584441462n), 26 | new PrimeField(4027184618003122424972590350825261965929648733675738730716654005365300998076n) 27 | ) 28 | } 29 | 30 | static g_3() { 31 | return new G1Group( 32 | new PrimeField(3353031288059533942658390886683067124040920775575537747144343083137631628272n), 33 | new PrimeField(19321533766552368860946552437480515441416830039777911637913418824951667761761n) 34 | ) 35 | } 36 | 37 | static zero() { 38 | return new G1Group( 39 | new PrimeField(0n), 40 | new PrimeField(0n), 41 | ) 42 | } 43 | 44 | assertEquals(p: G1Group, message?: string) { 45 | try { 46 | if (!this.x.equals(p.x)) { 47 | throw Error(`Field.assertEquals(): ${this.x.value} != ${p.x.value}`); 48 | } else if (!this.y.equals(p.y)) { 49 | throw Error(`Field.assertEquals(): ${this.y.value} != ${p.y.value}`); 50 | } 51 | return; 52 | } catch (err) { 53 | throw this.withMessage(err, message); 54 | } 55 | } 56 | 57 | withMessage(error: unknown, message?: string) { 58 | if (message === undefined || !(error instanceof Error)) return error; 59 | error.message = `${message}\n${error.message}`; 60 | return error; 61 | } 62 | 63 | isZero() { 64 | if(this.x.value == 0n && this.y.value == 0n) { 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | } 70 | 71 | equals(q: G1Group) { 72 | if(this.x.equals(q.x) && this.y.equals(q.y)) { 73 | return true; 74 | } else { 75 | return false; 76 | } 77 | } 78 | 79 | contains(q: G1Group) { 80 | } 81 | 82 | //add(p2: G1Group) { 83 | // let y2_minus_y1 = p2.y.sub(this.y); 84 | // let x2_minus_x1 = p2.x.sub(this.x); 85 | // let l = y2_minus_y1.div(x2_minus_x1); 86 | // 87 | // let new_x = ((l.square()).sub(this.x)).sub(p2.x); 88 | // let new_y = ((l.neg().mul(new_x)).add(l.mul(this.x))).sub(this.y) 89 | // 90 | // return new G1Group( 91 | // new_x, 92 | // new_y 93 | // ) 94 | //} 95 | 96 | add(p2: G1Group) { 97 | if (p2.isZero() == true) { 98 | return this; 99 | } else if (this.isZero()) { 100 | return p2; 101 | } 102 | 103 | if(this.equals(p2)) { 104 | return this.double(); 105 | } else if(this.x.equals(p2.x)) { 106 | return G1Group.zero(); 107 | } else { 108 | let y2_sub_y1 = p2.y.sub(this.y); 109 | let x2_sub_x1 = p2.x.sub(this.x); 110 | 111 | let x3 = y2_sub_y1.square().div(x2_sub_x1.square()).sub(this.x).sub(p2.x); 112 | let y3 = this.x.double().add(p2.x); 113 | y3 = y3.mul(y2_sub_y1.div(x2_sub_x1)); 114 | let y2_sub_y1_cube = y2_sub_y1.square().mul(y2_sub_y1); 115 | let x2_sub_x1_cube = x2_sub_x1.square().mul(x2_sub_x1); 116 | y3 = y3.sub(y2_sub_y1_cube.div(x2_sub_x1_cube)); 117 | y3 = y3.sub(this.y); 118 | 119 | return new G1Group( 120 | x3, 121 | y3 122 | ); 123 | } 124 | } 125 | 126 | // This works correctly. 127 | double() { 128 | let n_3 = new PrimeField(3n); 129 | let l = n_3.mul(this.x.square()).div(this.y.double()); 130 | let new_x = l.square().sub(this.x.double()); 131 | let new_y = l.neg().mul(new_x).add(l.mul(this.x).sub(this.y)); 132 | 133 | return new G1Group( 134 | new_x, 135 | new_y 136 | ); 137 | } 138 | 139 | neg() { 140 | return new G1Group( 141 | this.x, 142 | this.y.neg() 143 | ) 144 | } 145 | 146 | sub(q: G1Group) { 147 | return this.add(q.neg()); 148 | } 149 | } -------------------------------------------------------------------------------- /src/g2_new.test.ts: -------------------------------------------------------------------------------- 1 | import Fq from './fq'; 2 | import G2 from './g2_new'; 3 | 4 | describe('test G2 for BN254', function() { 5 | //G + G in projective coordinates is: 6 | 7 | //Parameters for G2 Generator Two 8 | //G2 x c0 9 | //18064657650266314310872833882734510304469342224960895762840452673540398385663 10 | //G2 x c1 11 | //15767209469806156760211170373387620603270210844572625444480773861832148323813 12 | //G2 y c0 13 | //18350387758438165722514006433324734852126505429007818091896560652419680779208 14 | //G2 y c1 15 | //2361120538552305763462588552289584032113666280040005078430227626567900900889 16 | //G2 z c0 17 | //11295011439305748432050915375304030887315222387144299555868531462511479541127 18 | //G2 z c1 19 | //21586188435259680269345972498488110271568572496353012928929868286300284796401 20 | 21 | it('add G2 example 1 comparison', function() { 22 | console.log("Add two generators"); 23 | let g2_generator = G2.generator(); 24 | let g2_generator_tw0 = g2_generator.add(g2_generator); 25 | 26 | console.log(g2_generator_tw0.x.c0.toBigInt()); 27 | console.log(g2_generator_tw0.x.c1.toBigInt()); 28 | console.log(g2_generator_tw0.y.c0.toBigInt()); 29 | console.log(g2_generator_tw0.y.c1.toBigInt()); 30 | console.log(g2_generator_tw0.z.c0.toBigInt()); 31 | console.log(g2_generator_tw0.z.c1.toBigInt()); 32 | }); 33 | 34 | //2G + G in projective coordinates is: 35 | 36 | //Parameters for G2 Generator Three 37 | //G2 x c0 38 | //5926278295631546541848273937383093992051957430605921609878905845370630022265 39 | //G2 x c1 40 | //20909916127742404614880828019765423001920616525637362121537299264611053476790 41 | //G2 y c0 42 | //17358201550752063428277563349129460395037108519145474230082971451955670087441 43 | //G2 y c1 44 | //4404603156095844367897556658925657679538289256686592432186242055289372496100 45 | //G2 z c0 46 | //14530595373659815785016120591752764358880173935729604246930766651462313748071 47 | //G2 z c1 48 | //20227398610188772026961144541529511078561459339161223150593172520713142552154 49 | 50 | it('add G2 example 2 comparison', function() { 51 | console.log("Add three generators"); 52 | let g2_generator = G2.generator(); 53 | let g2_generator_tw0 = g2_generator.add(g2_generator); 54 | let g2_generator_three = g2_generator_tw0.add(g2_generator); 55 | 56 | console.log(g2_generator_three.x.c0.toBigInt()); 57 | console.log(g2_generator_three.x.c1.toBigInt()); 58 | console.log(g2_generator_three.y.c0.toBigInt()); 59 | console.log(g2_generator_three.y.c1.toBigInt()); 60 | console.log(g2_generator_three.z.c0.toBigInt()); 61 | console.log(g2_generator_three.z.c1.toBigInt()); 62 | }); 63 | 64 | //G + G in projective coordinates is: 65 | //Parameters for G2 Generator Four by addition 66 | 67 | //Parameters for G2 Generator Four Affine 68 | //G2 x c0 69 | //18936818173480011669507163011118288089468827259971823710084038754632518263340 70 | //G2 x c1 71 | //18556147586753789634670778212244811446448229326945855846642767021074501673839 72 | //G2 y c0 73 | //18825831177813899069786213865729385895767511805925522466244528695074736584695 74 | //G2 y c1 75 | //13775476761357503446238925910346030822904460488609979964814810757616608848118 76 | it('double G2 example 1 comparison', function() { 77 | console.log("Double the generator"); 78 | let g2_generator = G2.generator(); 79 | let g2_generator_tw0 = g2_generator.add(g2_generator); 80 | let g2_generator_double = g2_generator_tw0.double(); 81 | //g2_generator_double = g2_generator_double.to_affine(); 82 | 83 | console.log(g2_generator_double.x.c0.toBigInt()); 84 | console.log(g2_generator_double.x.c1.toBigInt()); 85 | console.log(g2_generator_double.y.c0.toBigInt()); 86 | console.log(g2_generator_double.y.c1.toBigInt()); 87 | console.log(g2_generator_double.z.c0.toBigInt()); 88 | console.log(g2_generator_double.z.c1.toBigInt()); 89 | }); 90 | 91 | //2 * (2 * G) in affine coordinates is: 92 | 93 | it('double G2 example 2 comparison', function() { 94 | console.log("3*G + G = 2*(2*G) Affine Repr Check"); 95 | console.log("Double the generator"); 96 | let g2_generator = G2.generator(); 97 | let g2_generator_tw0 = g2_generator.double(); 98 | let g2_generator_double = g2_generator_tw0.double(); 99 | //g2_generator_double = g2_generator_double.to_affine(); 100 | 101 | console.log(g2_generator_double.x.c0.toBigInt()); 102 | console.log(g2_generator_double.x.c1.toBigInt()); 103 | console.log(g2_generator_double.y.c0.toBigInt()); 104 | console.log(g2_generator_double.y.c1.toBigInt()); 105 | console.log(g2_generator_double.z.c0.toBigInt()); 106 | console.log(g2_generator_double.z.c1.toBigInt()); 107 | }); 108 | 109 | }); -------------------------------------------------------------------------------- /src/g2_new.ts: -------------------------------------------------------------------------------- 1 | import Fq from "./fq"; 2 | import Fq2 from "./fq2"; 3 | import G2Affine from "./g2_affine"; 4 | 5 | export default class G2{ 6 | x: Fq2; 7 | y: Fq2; 8 | z: Fq2; 9 | 10 | constructor(x: Fq2, y: Fq2, z: Fq2) { 11 | // we can add checks later 12 | this.x = x; 13 | this.y = y; 14 | this.z = z; 15 | } 16 | 17 | static a = new Fq2( 18 | new Fq(0n), 19 | new Fq(0n) 20 | ); 21 | 22 | static b = new Fq2( 23 | new Fq(19485874751759354771024239261021720505790618469301721065564631296452457478373n), 24 | new Fq(266929791119991161246907387137283842545076965332900288569378510910307636690n) 25 | ); 26 | 27 | static curve_constant_3b = new Fq2( 28 | new Fq(14681138511599513868579906292550611339979233093309515871315818100066920017953n), 29 | new Fq(800789373359973483740722161411851527635230895998700865708135532730922910070n) 30 | ); 31 | 32 | static generator() { 33 | return new G2( 34 | new Fq2( 35 | new Fq(10857046999023057135944570762232829481370756359578518086990519993285655852781n), 36 | new Fq(11559732032986387107991004021392285783925812861821192530917403151452391805634n) 37 | ), 38 | new Fq2( 39 | new Fq(8495653923123431417604973247489272438418190587263600148770280649306958101930n), 40 | new Fq(4082367875863433681332203403145435568316851327593401208105741076214120093531n) 41 | ), 42 | new Fq2( 43 | new Fq(1n), 44 | new Fq(0n) 45 | ) 46 | ); 47 | } 48 | 49 | static identity() { 50 | return new G2( 51 | new Fq2( 52 | new Fq(0n), 53 | new Fq(0n) 54 | ), 55 | new Fq2( 56 | new Fq(1n), 57 | new Fq(0n) 58 | ), 59 | new Fq2( 60 | new Fq(0n), 61 | new Fq(0n) 62 | ) 63 | ); 64 | } 65 | 66 | withMessage(error: unknown, message?: string) { 67 | if (message === undefined || !(error instanceof Error)) return error; 68 | error.message = `${message}\n${error.message}`; 69 | return error; 70 | } 71 | 72 | add(other: G2) { 73 | let t0 = this.x.mul(other.x); 74 | let t1 = this.y.mul(other.y); 75 | let t2 = this.z.mul(other.z); 76 | let t3 = this.x.add(this.y); 77 | let t4 = other.x.add(other.y); 78 | t3 = t3.mul(t4); 79 | t4 = t0.add(t1); 80 | t3 = t3.sub(t4); 81 | t4 = this.y.add(this.z); 82 | let x3 = other.y.add(other.z); 83 | t4 = t4.mul(x3); 84 | x3 = t1.add(t2); 85 | t4 = t4.sub(x3); 86 | x3 = this.x.add(this.z); 87 | let y3 = other.x.add(other.z); 88 | x3 = x3.mul(y3); 89 | y3 = t0.add(t2); 90 | y3 = x3.sub(y3); 91 | x3 = t0.add(t0); 92 | t0 = x3.add(t0); 93 | 94 | //t2 = t2.mul_by_3b(); 95 | t2 = t2.mul(G2.curve_constant_3b); 96 | 97 | let z3 = t1.add(t2); 98 | t1 = t1.sub(t2); 99 | 100 | //y3 = y3.mul_by_3b(); 101 | y3 = y3.mul(G2.curve_constant_3b); 102 | 103 | x3 = t4.mul(y3); 104 | t2 = t3.mul(t1); 105 | x3 = t2.sub(x3); 106 | y3 = y3.mul(t0); 107 | t1 = t1.mul(z3); 108 | y3 = t1.add(y3); 109 | t0 = t0.mul(t3); 110 | z3 = z3.mul(t4); 111 | z3 = z3.add(t0); 112 | 113 | return new G2( 114 | x3, 115 | y3, 116 | z3 117 | ); 118 | } 119 | 120 | double() { 121 | let t0 = this.y.square(); 122 | let z3 = t0.add(t0); 123 | z3 = z3.add(z3); 124 | z3 = z3.add(z3); 125 | let t1 = this.y.mul(this.z); 126 | let t2 = this.z.square(); 127 | 128 | //t2 = t2.mul_by_3b(); 129 | t2 = t2.mul(G2.curve_constant_3b); 130 | 131 | let x3 = t2.mul(z3); 132 | let y3 = t0.add(t2); 133 | z3 = t1.mul(z3); 134 | t1 = t2.add(t2); 135 | t2 = t1.add(t2); 136 | t0 = t0.sub(t2); 137 | y3 = t0.mul(y3); 138 | y3 = x3.add(y3); 139 | t1 = this.x.mul(this.y); 140 | x3 = t0.mul(t1); 141 | x3 = x3.add(x3); 142 | 143 | return new G2( 144 | x3, 145 | y3, 146 | z3 147 | ); 148 | } 149 | 150 | to_affine() { 151 | let z_inv = this.z.invert(); 152 | let x = this.x.mul(z_inv); 153 | let y = this.y.mul(z_inv); 154 | 155 | // conditional_select?? 156 | 157 | // As an affine, let's have z = 0 with G1 158 | return new G2Affine( 159 | x, 160 | y 161 | ) 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /src/fq2.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'o1js/dist/node/lib/errors'; 2 | import Fq from './fq'; 3 | import Fq2 from './fq2' 4 | import { ForeignField, Field3} from 'o1js/dist/node/lib/gadgets/foreign-field'; 5 | 6 | /// An element of Fq2, represented by c0 + c1 * u; where u^2 = -1. 7 | describe('test Fq2 bn254', function() { 8 | 9 | // 1 + p = 1 mod p 10 | it('add Fq example 1', function() { 11 | 12 | }); 13 | 14 | // 1 + (p - 1) == 0 mod p 15 | it('add Fq example 2', function() { 16 | 17 | }); 18 | 19 | // 1 - p == 1 mod p 20 | it('sub Fq example 1', function() { 21 | 22 | }); 23 | 24 | // a + (b + c) == a + (c + b) == b + (c + a) 25 | it('Add Fq2', function() { 26 | console.log("Add two Fq2"); 27 | 28 | }); 29 | 30 | // a * (b * c) == a * (c * b) = b * (c * a) 31 | it('Mul Fq2', function() { 32 | console.log("Mul two Fq2"); 33 | // 34 | let nineFq2 = new Fq2( 35 | new Fq(9n), 36 | new Fq(1n) 37 | ); 38 | 39 | let x = new Fq2( 40 | new Fq(8n), 41 | new Fq(1n) 42 | ); 43 | 44 | 45 | }); 46 | 47 | // (9 + u) * (8 + u) == (71 + 17u) in normal form 48 | it('Mul Fq2', function() { 49 | console.log("Mul two Fq2"); 50 | 51 | // 9 + u 52 | let x = new Fq2( 53 | new Fq(9n), 54 | new Fq(1n) 55 | ); 56 | 57 | // 8 + u 58 | let y = new Fq2( 59 | new Fq(8n), 60 | new Fq(1n) 61 | ); 62 | 63 | let res = x.mul(y); 64 | console.log(res.c0.toBigInt()); 65 | console.log(res.c1.toBigInt()); 66 | 67 | }); 68 | 69 | // res c0: 8739174272930118246350991074272186610813592700785773244428337863339927508030n 70 | // res c1: 7427866275203353410928616081310925443454477010046778512011383141650n 71 | it('Mul Mont Fq2', function() { 72 | let x = new Fq2( 73 | new Fq(3713933137601676705464308040655462721727238505023389256005691570825n), 74 | new Fq(1n) 75 | ); 76 | 77 | let y = new Fq2( 78 | new Fq(3713933137601676705464308040655462721727238505023389256005691570825n), 79 | new Fq(1n) 80 | ); 81 | 82 | let res = x.mul(y); 83 | console.log(res.c0.toBigInt()); 84 | console.log(res.c1.toBigInt()); 85 | 86 | }); 87 | 88 | // a + a == 2*a 89 | it('Square Fq2', function() { 90 | 91 | }); 92 | 93 | // Square pseudorandom 94 | it('Square Fq2', function() { 95 | let c0 = new Fq(243396315656041018029605402550187233771055319601070064817557336100633225n); 96 | 97 | let x = new Fq2( 98 | c0, 99 | c0.double() 100 | ); 101 | 102 | let res = x.square(); 103 | console.log("Test square"); 104 | console.log(res.c0.toBigInt()); 105 | console.log(res.c1.toBigInt()); 106 | }); 107 | 108 | // a*a^-1 == O 109 | it('Invert Fq2', function() { 110 | 111 | }); 112 | 113 | // (2+2u) * (9+u) = (16+20u) 114 | it('Mul By Nonresidue Fq2', function() { 115 | 116 | }); 117 | 118 | // Random mul_by_nonresidue test 119 | it('Mul By Nonresidue Fq2', function() { 120 | let c0 = new Fq(243396315656041018029605402550187233771055319601070064817557336100633225n); 121 | 122 | let x = new Fq2( 123 | c0, 124 | c0.double() 125 | ); 126 | 127 | let res = x.mul_by_nonresidue(); 128 | 129 | console.log("Test mul_by_nonresidue"); 130 | console.log(res.c0.toBigInt()); 131 | console.log(res.c1.toBigInt()); 132 | }); 133 | 134 | 135 | // Random mul_by_nonresidue test 136 | it('Mul By Nonresidue Fq2', function() { 137 | let c0 = new Fq(243396315656041018029605402550187233771055319601070064817557336100633225n); 138 | 139 | let x = new Fq2( 140 | c0, 141 | c0.double() 142 | ); 143 | 144 | let res = x.mul_by_nonresidue(); 145 | 146 | console.log("Test mul_by_nonresidue"); 147 | console.log(res.c0.toBigInt()); 148 | console.log(res.c1.toBigInt()); 149 | }); 150 | 151 | // Random frobeinus map test 152 | it('Mul By Nonresidue Fq2', function() { 153 | let c0 = new Fq(243396315656041018029605402550187233771055319601070064817557336100633225n); 154 | 155 | let x = new Fq2( 156 | c0, 157 | c0.double() 158 | ); 159 | 160 | let res0 = x.frobenius_map(0n); 161 | let res1 = x.frobenius_map(1n); 162 | 163 | console.log("Test frob 0"); 164 | console.log(res0.c0.toBigInt()); 165 | console.log(res0.c1.toBigInt()); 166 | 167 | console.log("Test frob 1"); 168 | console.log(res1.c0.toBigInt()); 169 | console.log(res1.c1.toBigInt()); 170 | }); 171 | 172 | // comparison test 173 | it('Invert Fq2', function() { 174 | let x = new Fq2( 175 | new Fq(2n), 176 | new Fq(3n) 177 | ); 178 | 179 | let res = x.invert(); 180 | console.log("Test invert"); 181 | console.log(res.c0.toBigInt()); 182 | console.log(res.c1.toBigInt()); 183 | }); 184 | 185 | }); -------------------------------------------------------------------------------- /src/g2.ts: -------------------------------------------------------------------------------- 1 | import Fp2 from './fp2'; 2 | import PrimeField from './primeField'; 3 | 4 | export default class G2Group{ 5 | x: Fp2; 6 | y: Fp2; 7 | z: Fp2; 8 | 9 | constructor(x: Fp2, y: Fp2) { 10 | // we can add checks later 11 | this.x = x; 12 | this.y = y; 13 | this.z = Fp2.one(); 14 | // on curve check 15 | } 16 | 17 | static a = new Fp2(new PrimeField(0n), new PrimeField(0n)); 18 | static b = new Fp2(new PrimeField(19485874751759354771024239261021720505790618469301721065564631296452457478373n), new PrimeField(266929791119991161246907387137283842545076965332900288569378510910307636690n)); 19 | 20 | static generator() { 21 | return new G2Group( 22 | new Fp2(new PrimeField(10857046999023057135944570762232829481370756359578518086990519993285655852781n), new PrimeField(11559732032986387107991004021392285783925812861821192530917403151452391805634n)), 23 | new Fp2(new PrimeField(8495653923123431417604973247489272438418190587263600148770280649306958101930n), new PrimeField(4082367875863433681332203403145435568316851327593401208105741076214120093531n)), 24 | ); 25 | } 26 | 27 | static zero() { 28 | return new G2Group( 29 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 30 | new Fp2(new PrimeField(0n), new PrimeField(0n)) 31 | ) 32 | } 33 | 34 | static g_3() { 35 | return new G2Group( 36 | new Fp2(new PrimeField(2725019753478801796453339367788033689375851816420509565303521482350756874229n), new PrimeField(7273165102799931111715871471550377909735733521218303035754523677688038059653n)), 37 | new Fp2(new PrimeField(2512659008974376214222774206987427162027254181373325676825515531566330959255n), new PrimeField(957874124722006818841961785324909313781880061366718538693995380805373202866n)) 38 | ) 39 | } 40 | 41 | static to_affine(p:G2Group, z: Fp2) { 42 | let x_affine = p.x.div(z.square()); 43 | let y_affine = p.y.div(z.square().mul(z)); 44 | 45 | //console.log("HEY THIS IS Z"); 46 | //console.log(z); 47 | 48 | return new G2Group( 49 | x_affine, 50 | y_affine 51 | ); 52 | } 53 | 54 | assertEquals(p: G2Group, message?: string) { 55 | try { 56 | if (!this.x.equals(p.x)) { 57 | throw Error(`Field.assertEquals(): ${this.x.c0} != ${p.x.c0} or ${this.x.c1} != ${p.x.c1}`); 58 | } else if (!this.y.equals(p.y)) { 59 | throw Error(`Field.assertEquals(): ${this.y.c0} != ${p.y.c0} or ${this.y.c1} != ${p.y.c1} `); 60 | } 61 | return; 62 | } catch (err) { 63 | throw this.withMessage(err, message); 64 | } 65 | } 66 | 67 | withMessage(error: unknown, message?: string) { 68 | if (message === undefined || !(error instanceof Error)) return error; 69 | error.message = `${message}\n${error.message}`; 70 | return error; 71 | } 72 | 73 | isZero() { 74 | if(this.x.isZero() && this.y.isZero()) { 75 | return true; 76 | } else { 77 | return false; 78 | } 79 | } 80 | 81 | equals(q: G2Group) { 82 | if(this.x.equals(q.x) && this.y.equals(q.y)) { 83 | return true; 84 | } else { 85 | return false; 86 | } 87 | } 88 | 89 | contains(q: G2Group) { 90 | } 91 | 92 | 93 | add(p2: G2Group) { 94 | if (p2.isZero() == true) { 95 | return this; 96 | } else if (this.isZero()) { 97 | return p2; 98 | } 99 | 100 | if(this.equals(p2)) { 101 | return this.double(); 102 | } else if(this.x.equals(p2.x)) { 103 | return G2Group.zero(); 104 | } else { 105 | let y2_sub_y1 = p2.y.sub(this.y); 106 | let x2_sub_x1 = p2.x.sub(this.x); 107 | 108 | let x3 = y2_sub_y1.square().div(x2_sub_x1.square()).sub(this.x).sub(p2.x); 109 | let y3 = this.x.double().add(p2.x); 110 | y3 = y3.mul(y2_sub_y1.div(x2_sub_x1)); 111 | let y2_sub_y1_cube = y2_sub_y1.square().mul(y2_sub_y1); 112 | let x2_sub_x1_cube = x2_sub_x1.square().mul(x2_sub_x1); 113 | y3 = y3.sub(y2_sub_y1_cube.div(x2_sub_x1_cube)); 114 | y3 = y3.sub(this.y); 115 | 116 | return new G2Group( 117 | x3, 118 | y3 119 | ); 120 | } 121 | } 122 | 123 | // This works correctly. 124 | double() { 125 | let n_3 = new Fp2(new PrimeField(3n), new PrimeField(0n)); 126 | let l = n_3.mul(this.x.square()).div(this.y.double()); 127 | let new_x = l.square().sub(this.x.double()); 128 | let new_y = l.neg().mul(new_x).add(l.mul(this.x).sub(this.y)); 129 | 130 | return new G2Group( 131 | new_x, 132 | new_y 133 | ); 134 | } 135 | 136 | neg() { 137 | return new G2Group( 138 | this.x, 139 | this.y.neg() 140 | ) 141 | } 142 | 143 | sub(q: G2Group) { 144 | return this.add(q.neg()); 145 | } 146 | } -------------------------------------------------------------------------------- /src/fp2.ts: -------------------------------------------------------------------------------- 1 | import {Field, Poseidon} from 'o1js'; 2 | import PrimeField from './primeField'; 3 | 4 | export default class Fp2{ 5 | // An element of Fp2 is respresented by c0 + c1 * u 6 | c0: PrimeField; 7 | c1: PrimeField; 8 | 9 | constructor(c0: PrimeField, c1: PrimeField) { 10 | // we can add checks later 11 | this.c0 = c0; 12 | this.c1 = c1; 13 | } 14 | 15 | static zero() { 16 | return new Fp2(new PrimeField(0n), new PrimeField(0n)); 17 | } 18 | 19 | static one() { 20 | return new Fp2(new PrimeField(1n),new PrimeField(0n)); 21 | } 22 | 23 | 24 | add(y: Fp2) { 25 | return new Fp2( 26 | this.c0.add(y.c0), 27 | this.c1.add(y.c1) 28 | ); 29 | } 30 | 31 | sub(y: Fp2) { 32 | return new Fp2( 33 | this.c0.sub(y.c0), 34 | this.c1.sub(y.c1) 35 | ); 36 | } 37 | 38 | mul(y: Fp2) { 39 | let t1 = this.c0.mul(y.c0); 40 | let t0 = this.c0.add(this.c1); 41 | let t2 = this.c1.mul(y.c1); 42 | 43 | let c1 = y.c0.add(y.c1); 44 | let c0 = t1.sub(t2); 45 | 46 | t1 = t1.add(t2); 47 | t0 = t0.mul(c1); 48 | c1 = t0.sub(t1); 49 | 50 | return new Fp2(c0, c1); 51 | } 52 | 53 | double() { 54 | return new Fp2( 55 | this.c0.add(this.c0), 56 | this.c1.add(this.c1) 57 | ); 58 | } 59 | 60 | square() { 61 | let ab = this.c0.mul(this.c1); 62 | let c0c1 = this.c0.add(this.c1); 63 | let c0 = this.c1.neg(); 64 | c0 = c0.add(this.c0); 65 | c0 = c0.mul(c0c1); 66 | c0 = c0.sub(ab); 67 | 68 | return new Fp2 ( 69 | c0.add(ab), 70 | ab.add(ab) 71 | ); 72 | } 73 | 74 | neg() { 75 | return new Fp2( 76 | this.c0.neg(), 77 | this.c1.neg() 78 | ); 79 | } 80 | 81 | conjugate() { 82 | return new Fp2( 83 | this.c0, 84 | this.c1.neg() 85 | ); 86 | } 87 | 88 | // do we need to return bool? 89 | assertEquals(y: Fp2) { 90 | this.c0.assertEquals(y.c0); 91 | this.c1.assertEquals(y.c1); 92 | } 93 | 94 | equals(y: Fp2) { 95 | if(this.c0.equals(y.c0) && this.c1.equals(y.c1)) { 96 | return true; 97 | } else { 98 | return false; 99 | } 100 | } 101 | 102 | notEquals(y: Fp2) { 103 | if(this.c0.equals(y.c0) && this.c1.equals(y.c1)) { 104 | return false; 105 | } else { 106 | return true; 107 | } 108 | } 109 | 110 | // do we need to return bool? 111 | // now, isZero() returns bool 112 | isZero() { 113 | //this.c0.assertEquals(Field(0)); 114 | //this.c1.assertEquals(Field(0)); 115 | 116 | if(this.c0.equals(new PrimeField(0n)) && this.c1.equals(new PrimeField(0n))) { 117 | return true; 118 | } else { 119 | return false; 120 | } 121 | } 122 | 123 | // do we need to return bool? 124 | isOne() { 125 | this.c0.assertEquals(new PrimeField(1n)); 126 | this.c1.assertEquals(new PrimeField(0n)); 127 | } 128 | 129 | // Algorithm 7 from: https://eprint.iacr.org/2010/354.pdf 130 | mul_by_b0(b0: PrimeField) { 131 | return new Fp2( 132 | this.c0.mul(b0), 133 | this.c1.mul(b0) 134 | ); 135 | } 136 | 137 | // Algorithm 8 from: https://eprint.iacr.org/2010/354.pdf 138 | invert() { 139 | let t0 = this.c0.mul(this.c0); 140 | let t1 = this.c1.mul(this.c1); 141 | t0 = t0.add(t1); 142 | t1 = t0.inv(); 143 | let c0 = t1.mul(this.c0); 144 | let c1 = this.c1.mul(t1); 145 | c1 = c1.neg(); 146 | 147 | return new Fp2( 148 | c0, 149 | c1 150 | ); 151 | } 152 | 153 | div(x: Fp2) { 154 | return this.mul(x.invert()); 155 | } 156 | 157 | // We need to implement quadratic nonresidue of Pallas as temporary 158 | // Implemented quadratic nonresidue of BN254 159 | mul_by_nonresidue() { 160 | let t0 = this.c0; 161 | let t1 = this.c1; 162 | 163 | let p2 = this.double(); 164 | let p4 = p2.double(); 165 | let p8 = p4.double(); 166 | 167 | let c0 = p8.c0.add(t0); 168 | c0 = c0.sub(t1); 169 | 170 | let c1 = p8.c1.add(t1); 171 | c1 = c1.add(t0); 172 | 173 | return new Fp2( 174 | c0, 175 | c1 176 | ); 177 | } 178 | 179 | // parameters for bn254 180 | mul_by_non_residue_1_power_1() { 181 | let y = new Fp2( 182 | new PrimeField(8376118865763821496583973867626364092589906065868298776909617916018768340080n), 183 | new PrimeField(16469823323077808223889137241176536799009286646108169935659301613961712198316n) 184 | ); 185 | return this.mul(y); 186 | } 187 | 188 | mul_by_non_residue_1_power_2() { 189 | let y = new Fp2( 190 | new PrimeField(21575463638280843010398324269430826099269044274347216827212613867836435027261n), 191 | new PrimeField(10307601595873709700152284273816112264069230130616436755625194854815875713954n) 192 | ); 193 | return this.mul(y); 194 | } 195 | 196 | mul_by_non_residue_1_power_3() { 197 | let y = new Fp2( 198 | new PrimeField(2821565182194536844548159561693502659359617185244120367078079554186484126554n), 199 | new PrimeField(3505843767911556378687030309984248845540243509899259641013678093033130930403n) 200 | ); 201 | return this.mul(y); 202 | } 203 | 204 | mul_by_non_residue_1_power_4() { 205 | let y = new Fp2( 206 | new PrimeField(2581911344467009335267311115468803099551665605076196740867805258568234346338n), 207 | new PrimeField(19937756971775647987995932169929341994314640652964949448313374472400716661030n) 208 | ); 209 | return this.mul(y); 210 | } 211 | 212 | mul_by_non_residue_1_power_5() { 213 | let y = new Fp2( 214 | new PrimeField(685108087231508774477564247770172212460312782337200605669322048753928464687n), 215 | new PrimeField(8447204650696766136447902020341177575205426561248465145919723016860428151883n) 216 | ); 217 | return this.mul(y); 218 | } 219 | 220 | mul_by_non_residue_2_power_1() { 221 | return this.mul_by_b0(new PrimeField(21888242871839275220042445260109153167277707414472061641714758635765020556617n)); 222 | } 223 | 224 | mul_by_non_residue_2_power_2() { 225 | return this.mul_by_b0(new PrimeField(21888242871839275220042445260109153167277707414472061641714758635765020556616n)); 226 | } 227 | 228 | mul_by_non_residue_2_power_3() { 229 | return this.mul_by_b0(new PrimeField(21888242871839275222246405745257275088696311157297823662689037894645226208582n)); 230 | } 231 | 232 | mul_by_non_residue_2_power_4() { 233 | return this.mul_by_b0(new PrimeField(2203960485148121921418603742825762020974279258880205651966n)); 234 | } 235 | 236 | mul_by_non_residue_2_power_5() { 237 | return this.mul_by_b0(new PrimeField(2203960485148121921418603742825762020974279258880205651967n)); 238 | } 239 | 240 | mul_by_non_residue_3_power_1() { 241 | let y = new Fp2( 242 | new PrimeField(11697423496358154304825782922584725312912383441159505038794027105778954184319n), 243 | new PrimeField(303847389135065887422783454877609941456349188919719272345083954437860409601n) 244 | ); 245 | return this.mul(y); 246 | } 247 | 248 | mul_by_non_residue_3_power_2() { 249 | let y = new Fp2( 250 | new PrimeField(3772000881919853776433695186713858239009073593817195771773381919316419345261n), 251 | new PrimeField(2236595495967245188281701248203181795121068902605861227855261137820944008926n) 252 | ); 253 | return this.mul(y); 254 | } 255 | 256 | mul_by_non_residue_3_power_3() { 257 | let y = new Fp2( 258 | new PrimeField(19066677689644738377698246183563772429336693972053703295610958340458742082029n), 259 | new PrimeField(18382399103927718843559375435273026243156067647398564021675359801612095278180n) 260 | ); 261 | return this.mul(y); 262 | } 263 | 264 | mul_by_non_residue_3_power_4() { 265 | let y = new Fp2( 266 | new PrimeField(5324479202449903542726783395506214481928257762400643279780343368557297135718n), 267 | new PrimeField(16208900380737693084919495127334387981393726419856888799917914180988844123039n) 268 | ); 269 | return this.mul(y); 270 | } 271 | 272 | mul_by_non_residue_3_power_5() { 273 | let y = new Fp2( 274 | new PrimeField(8941241848238582420466759817324047081148088512956452953208002715982955420483n), 275 | new PrimeField(10338197737521362862238855242243140895517409139741313354160881284257516364953n) 276 | ); 277 | return this.mul(y); 278 | } 279 | } -------------------------------------------------------------------------------- /src/fp6.ts: -------------------------------------------------------------------------------- 1 | import Fp2 from './fp2'; 2 | import PrimeField from './primeField'; 3 | 4 | export default class Fp6{ 5 | // c0 + c1 * v + c2 * v^2 6 | c0: Fp2; 7 | c1: Fp2; 8 | c2: Fp2; 9 | 10 | constructor(c0: Fp2, c1: Fp2, c2: Fp2) { 11 | // we can add checks later 12 | this.c0 = c0; 13 | this.c1 = c1; 14 | this.c2 = c2; 15 | } 16 | 17 | static zero() { 18 | return new Fp6( 19 | Fp2.zero(), 20 | Fp2.zero(), 21 | Fp2.zero() 22 | ); 23 | } 24 | 25 | static one() { 26 | return new Fp6( 27 | Fp2.one(), 28 | Fp2.zero(), 29 | Fp2.zero() 30 | ); 31 | } 32 | 33 | add(y: Fp6) { 34 | return new Fp6( 35 | this.c0.add(y.c0), 36 | this.c1.add(y.c1), 37 | this.c2.add(y.c2) 38 | ); 39 | } 40 | 41 | sub(y: Fp6) { 42 | return new Fp6( 43 | this.c0.sub(y.c0), 44 | this.c1.sub(y.c1), 45 | this.c2.sub(y.c2) 46 | ); 47 | } 48 | 49 | mul(y: Fp6) { 50 | let a_a = this.c0.mul(y.c0); 51 | let b_b = this.c1.mul(y.c1); 52 | let c_c = this.c2.mul(y.c2); 53 | 54 | // Construct t1 55 | let t1 = y.c1; 56 | t1 = t1.add(y.c2); 57 | 58 | let tmp = this.c1.add(this.c2); 59 | t1 = t1.mul(tmp); 60 | t1 = t1.sub(b_b); 61 | t1 = t1.sub(c_c); 62 | t1 = t1.mul_by_nonresidue(); 63 | t1 = t1.add(a_a); 64 | 65 | // Construct t3 66 | let t3 = y.c0; 67 | t3 = t3.add(y.c2); 68 | 69 | tmp = this.c0.add(this.c2); 70 | t3 = t3.mul(tmp); 71 | t3 = t3.sub(a_a); 72 | t3 = t3.add(b_b); 73 | t3 = t3.sub(c_c); 74 | 75 | // Construct t2 76 | let t2 = y.c0; 77 | t2 = t2.add(y.c1); 78 | 79 | tmp = this.c0.add(this.c1); 80 | t2 = t2.mul(tmp); 81 | t2 = t2.sub(a_a); 82 | t2 = t2.sub(b_b); 83 | let c_c_mul_by_nonres = c_c.mul_by_nonresidue(); 84 | t2 = t2.add(c_c_mul_by_nonres); 85 | 86 | return new Fp6( 87 | t1, 88 | t2, 89 | t3 90 | ); 91 | } 92 | 93 | double() { 94 | return new Fp6( 95 | this.c0.double(), 96 | this.c1.double(), 97 | this.c2.double() 98 | ) 99 | } 100 | 101 | // Algorithm 16 from: https://eprint.iacr.org/2010/354.pdf 102 | // this won't work due to pallas 103 | square() { 104 | let c4 = this.c0.mul(this.c1); 105 | c4 = c4.double(); 106 | let c5 = this.c2.square(); 107 | let tmp = c5.mul_by_nonresidue(); 108 | let c1 = tmp.add(c4); 109 | let c2 = c4.sub(c5); 110 | let c3 = this.c0.square(); 111 | c4 = this.c0.sub(this.c1); 112 | c4 = c4.add(this.c2); 113 | c5 = this.c1.mul(this.c2); 114 | c5 = c5.double(); 115 | c4 = c4.square(); 116 | tmp = c5.mul_by_nonresidue(); 117 | let c0 = tmp.add(c3); 118 | c2 = c2.add(c4); 119 | c2 = c2.add(c5); 120 | c2 = c2.sub(c3); 121 | 122 | return new Fp6( 123 | c0, 124 | c1, 125 | c2 126 | ); 127 | } 128 | 129 | neg() { 130 | return new Fp6( 131 | this.c0.neg(), 132 | this.c1.neg(), 133 | this.c2.neg() 134 | ); 135 | } 136 | 137 | assertEquals(y: Fp6) { 138 | this.c0.assertEquals(y.c0); 139 | this.c1.assertEquals(y.c1); 140 | this.c2.assertEquals(y.c2); 141 | } 142 | 143 | isZero() { 144 | this.c0.assertEquals(new Fp2(new PrimeField(0n), new PrimeField(0n))); 145 | this.c1.assertEquals(new Fp2(new PrimeField(0n), new PrimeField(0n))); 146 | this.c2.assertEquals(new Fp2(new PrimeField(0n), new PrimeField(0n))); 147 | } 148 | 149 | isOne() { 150 | this.c0.assertEquals(new Fp2(new PrimeField(1n), new PrimeField(0n))); 151 | this.c1.assertEquals(new Fp2(new PrimeField(0n), new PrimeField(0n))); 152 | this.c2.assertEquals(new Fp2(new PrimeField(0n), new PrimeField(0n))); 153 | } 154 | 155 | invert() { 156 | let c0 = this.c2; 157 | c0 = c0.mul_by_nonresidue(); 158 | c0 = c0.mul(this.c1); 159 | c0 = c0.neg(); 160 | 161 | let c0s = this.c0; 162 | c0s = c0s.square(); 163 | c0 = c0.add(c0s); 164 | 165 | let c1 = this.c2; 166 | c1 = c1.square(); 167 | c1 = c1.mul_by_nonresidue(); 168 | 169 | let c01 = this.c0; 170 | c01 = c01.mul(this.c1); 171 | c1 = c1.sub(c01); 172 | 173 | let c2 = this.c1; 174 | c2 = c2.square(); 175 | let c02 = this.c0; 176 | c02 = c02.mul(this.c2); 177 | c2 = c2.sub(c02); 178 | 179 | let tmp1 = this.c2; 180 | tmp1 = tmp1.mul(c1); 181 | let tmp2 = this.c1; 182 | tmp2 = tmp2.mul(c2); 183 | tmp1 = tmp1.add(tmp2); 184 | tmp1 = tmp1.mul_by_nonresidue(); 185 | tmp2 = this.c0; 186 | tmp2 = tmp2.mul(c0); 187 | tmp1 = tmp1.add(tmp2); 188 | 189 | let tmp = tmp1.invert(); 190 | c0 = tmp.mul(c0); 191 | c1 = tmp.mul(c1); 192 | c2 = tmp.mul(c2); 193 | 194 | return new Fp6( 195 | c0, 196 | c1, 197 | c2 198 | ); 199 | } 200 | 201 | // Algorithm 17 from: https://eprint.iacr.org/2010/354.pdf 202 | invert_x() { 203 | let t0 = this.c0.square(); 204 | let t1 = this.c1.square(); 205 | let t2 = this.c2.square(); 206 | 207 | let t3 = this.c0.mul(this.c1); 208 | let t4 = this.c0.mul(this.c2); 209 | let t5 = this.c2.mul(this.c1); 210 | 211 | let tmp = t5.mul_by_nonresidue(); 212 | let c0 = t0.sub(tmp); 213 | 214 | tmp = t2.mul_by_nonresidue(); 215 | let c1 = tmp.sub(t3); 216 | 217 | let c2 = t1.mul(t4); 218 | 219 | let t6 = this.c0.mul(c0); 220 | 221 | tmp = this.c2.mul(c1); 222 | tmp = tmp.mul_by_nonresidue(); 223 | t6 = t6.add(tmp); 224 | 225 | tmp = this.c1.mul(c2); 226 | tmp = tmp.mul_by_nonresidue(); 227 | t6 = t6.add(tmp); 228 | 229 | t6 = t6.invert(); 230 | 231 | c0 = c0.mul(t6); 232 | c1 = c1.mul(t6); 233 | c2 = c2.mul(t6); 234 | 235 | return new Fp6( 236 | c0, 237 | c1, 238 | c2 239 | ); 240 | } 241 | 242 | // Multiply by cubic nonresidue v 243 | // c0, c1, c2 -> c2, c0, c1 244 | 245 | mul_by_nonresidue() { 246 | return new Fp6( 247 | this.c2.mul_by_nonresidue(), 248 | this.c0, 249 | this.c1 250 | ); 251 | } 252 | 253 | mul_torus() { 254 | } 255 | 256 | mul_plus_one_b1(y: Fp6) { 257 | } 258 | 259 | // gnark-crypto 260 | mulByE2(yCopy: Fp2) { 261 | return new Fp6( 262 | this.c0.mul(yCopy), 263 | this.c1.mul(yCopy), 264 | this.c2.mul(yCopy) 265 | ) 266 | } 267 | 268 | // gnark-crypto 269 | mulBy12(b1: Fp2, b2: Fp2) { 270 | let t1 = this.c1.mul(b1); 271 | let t2 = this.c2.mul(b2); 272 | let c0 = this.c2.mul(b2); 273 | let tmp = b1.add(b2); 274 | c0 = c0.mul(tmp); 275 | c0 = c0.sub(t1); 276 | c0 = c0.sub(t2); 277 | c0 = c0.mul_by_nonresidue(); // Check this again! They might differ 278 | let c1 = this.c0.add(this.c1); 279 | c1 = c1.mul(b1); 280 | c1 = c1.sub(t1); 281 | tmp = t2.mul_by_nonresidue(); // Check this again! 282 | c1 = c1.add(tmp); 283 | tmp = this.c0.add(this.c2); 284 | let c2 = b2.mul(tmp); 285 | c2 = c2.sub(t2); 286 | c2 = c2.add(t1); 287 | 288 | return new Fp6( 289 | c0, 290 | c1, 291 | c2 292 | ); 293 | } 294 | 295 | // gnark-crypto 296 | mulBy01(c0: Fp2, c1: Fp2) { 297 | let a = this.c0.mul(c0); 298 | let b = this.c1.mul(c1); 299 | 300 | let tmp = this.c1.add(this.c2); 301 | let t0 = tmp.mul(c1); 302 | t0 = t0.sub(b); 303 | t0 = t0.mul_by_nonresidue(); 304 | t0 = t0.add(a); 305 | 306 | tmp = this.c0.add(this.c2); 307 | let t2 = tmp.mul(c0); 308 | t2 = t2.sub(a); 309 | t2 = t2.add(b); 310 | 311 | let t1 = c0.add(c1); 312 | tmp = this.c0.add(this.c1); 313 | t1 = t1.mul(tmp); 314 | t1 = t1.sub(a); 315 | t1 = t1.sub(b); 316 | 317 | return new Fp6( 318 | t0, 319 | t1, 320 | t2 321 | ); 322 | } 323 | 324 | // gnark-crypto 325 | mulBy1(c1: Fp2) { 326 | let b = this.c1.mul(c1); 327 | 328 | let tmp = this.c1.add(this.c2); 329 | let t0 = c1.mul(tmp); 330 | t0 = t0.sub(b); 331 | t0 = t0.mul_by_nonresidue(); 332 | 333 | tmp = this.c0.add(this.c1); 334 | let t1 = c1.mul(tmp); 335 | t1 = t1.sub(b); 336 | 337 | return new Fp6( 338 | t0, 339 | t1, 340 | b 341 | ); 342 | } 343 | } -------------------------------------------------------------------------------- /src/fp12.ts: -------------------------------------------------------------------------------- 1 | import PrimeField from './primeField'; 2 | import Fp2 from './fp2'; 3 | import Fp6 from './fp6'; 4 | 5 | export default class Fp12{ 6 | // c0 + c1 * w 7 | c0: Fp6; 8 | c1: Fp6; 9 | 10 | constructor(c0: Fp6, c1: Fp6) { 11 | // we can add checks later 12 | this.c0 = c0; 13 | this.c1 = c1; 14 | } 15 | 16 | static zero() { 17 | return new Fp12( 18 | Fp6.zero(), 19 | Fp6.zero() 20 | ); 21 | } 22 | 23 | static one() { 24 | return new Fp12( 25 | Fp6.one(), 26 | Fp6.zero() 27 | ); 28 | } 29 | 30 | add(y: Fp12) { 31 | return new Fp12( 32 | this.c0.add(y.c0), 33 | this.c1.add(y.c1) 34 | ); 35 | } 36 | 37 | sub(y: Fp12) { 38 | return new Fp12( 39 | this.c0.sub(y.c0), 40 | this.c1.sub(y.c1) 41 | ); 42 | } 43 | 44 | mul(y: Fp12) { 45 | let t0 = this.c0.mul(y.c0); 46 | let t1 = this.c1.mul(y.c1); 47 | let t2 = y.c0.add(y.c1); 48 | 49 | let c1 = this.c1.add(this.c0); 50 | c1 = c1.mul(t2); 51 | c1 = c1.sub(t0); 52 | c1 = c1.sub(t1); 53 | 54 | t1 = t1.mul_by_nonresidue(); 55 | let c0 = t0.add(t1); 56 | 57 | return new Fp12( 58 | c0, 59 | c1 60 | ); 61 | } 62 | 63 | double() { 64 | return new Fp12( 65 | this.c0.double(), 66 | this.c1.double() 67 | ) 68 | } 69 | 70 | square() { 71 | let ab = this.c0.mul(this.c1); 72 | let c0c1 = this.c0.add(this.c1); 73 | let c0 = this.c1.mul_by_nonresidue(); 74 | c0 = c0.add(this.c0); 75 | c0 = c0.mul(c0c1); 76 | c0 = c0.sub(ab); 77 | 78 | let c1 = ab.add(ab); 79 | let tmp = ab.mul_by_nonresidue(); 80 | c0 = c0.sub(tmp); 81 | 82 | return new Fp12( 83 | c0, 84 | c1 85 | ); 86 | } 87 | 88 | neg() { 89 | return new Fp12( 90 | this.c0.neg(), 91 | this.c1.neg() 92 | ); 93 | } 94 | 95 | conjugate() { 96 | return new Fp12( 97 | this.c0, 98 | this.c1.neg() 99 | ); 100 | } 101 | 102 | assertEquals(y: Fp12) { 103 | this.c0.assertEquals(y.c0); 104 | this.c1.assertEquals(y.c1); 105 | } 106 | 107 | isZero() { 108 | this.c0.assertEquals(new Fp6( 109 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 110 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 111 | new Fp2(new PrimeField(0n), new PrimeField(0n)))); 112 | 113 | this.c1.assertEquals(new Fp6( 114 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 115 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 116 | new Fp2(new PrimeField(0n), new PrimeField(0n)))); 117 | } 118 | 119 | isOne() { 120 | this.c0.assertEquals(new Fp6( 121 | new Fp2(new PrimeField(1n), new PrimeField(0n)), 122 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 123 | new Fp2(new PrimeField(0n), new PrimeField(0n)))); 124 | 125 | this.c1.assertEquals(new Fp6( 126 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 127 | new Fp2(new PrimeField(0n), new PrimeField(0n)), 128 | new Fp2(new PrimeField(0n), new PrimeField(0n)))); 129 | } 130 | 131 | invert() { 132 | let c0s = this.c0.mul(this.c0); 133 | let c1s = this.c1.mul(this.c1); 134 | c1s = c1s.mul_by_nonresidue(); 135 | c0s = c0s.sub(c1s); 136 | let c0 = c0s.invert(); 137 | let c1 = c0s.invert(); 138 | c0 = c0.mul(this.c0); 139 | c1 = c1.mul(this.c1); 140 | c1 = c1.neg(); 141 | 142 | return new Fp12( 143 | c0, 144 | c1 145 | ); 146 | } 147 | 148 | // Algorithm 28 from: https://eprint.iacr.org/2010/354.pdf 149 | frobenius() { 150 | let t1 = this.c0.c0.conjugate(); 151 | let t2 = this.c1.c0.conjugate(); 152 | let t3 = this.c0.c1.conjugate(); 153 | let t4 = this.c1.c1.conjugate(); 154 | let t5 = this.c0.c2.conjugate(); 155 | let t6 = this.c1.c2.conjugate(); 156 | 157 | t2 = t2.mul_by_non_residue_1_power_1(); 158 | t3 = t3.mul_by_non_residue_1_power_2(); 159 | t4 = t4.mul_by_non_residue_1_power_3(); 160 | t5 = t5.mul_by_non_residue_1_power_4(); 161 | t6 = t6.mul_by_non_residue_1_power_5(); 162 | 163 | let c0 = new Fp6( 164 | t1, 165 | t3, 166 | t5 167 | ); 168 | 169 | let c1 = new Fp6( 170 | t2, 171 | t4, 172 | t6 173 | ); 174 | 175 | return new Fp12( 176 | c0, 177 | c1 178 | ); 179 | } 180 | 181 | // Algorithm 29 from: https://eprint.iacr.org/2010/354.pdf 182 | frobenius_square() { 183 | let t1 = this.c0.c0; 184 | let t2 = this.c1.c0.mul_by_non_residue_2_power_1(); 185 | let t3 = this.c0.c1.mul_by_non_residue_2_power_2(); 186 | let t4 = this.c1.c1.mul_by_non_residue_2_power_3(); 187 | let t5 = this.c0.c2.mul_by_non_residue_2_power_4(); 188 | let t6 = this.c1.c2.mul_by_non_residue_2_power_5(); 189 | 190 | let c0 = new Fp6( 191 | t1, 192 | t3, 193 | t5 194 | ); 195 | 196 | let c1 = new Fp6( 197 | t2, 198 | t4, 199 | t6 200 | ); 201 | 202 | return new Fp12( 203 | c0, 204 | c1 205 | ); 206 | } 207 | 208 | // Algorithm 30 from: https://eprint.iacr.org/2010/354.pdf 209 | frobenius_cube() { 210 | let t1 = this.c0.c0.conjugate(); 211 | let t2 = this.c1.c0.conjugate(); 212 | let t3 = this.c0.c1.conjugate(); 213 | let t4 = this.c1.c1.conjugate(); 214 | let t5 = this.c0.c2.conjugate(); 215 | let t6 = this.c1.c2.conjugate(); 216 | 217 | t2 = t2.mul_by_non_residue_3_power_1(); 218 | t3 = t3.mul_by_non_residue_3_power_2(); 219 | t4 = t4.mul_by_non_residue_3_power_3(); 220 | t5 = t5.mul_by_non_residue_3_power_4(); 221 | t6 = t6.mul_by_non_residue_3_power_5(); 222 | 223 | let c0 = new Fp6( 224 | t1, 225 | t3, 226 | t5 227 | ); 228 | 229 | let c1 = new Fp6( 230 | t2, 231 | t4, 232 | t6 233 | ); 234 | 235 | return new Fp12( 236 | c0, 237 | c1 238 | ); 239 | } 240 | 241 | // Granger-Scott's cyclotomic square 242 | // https://eprint.iacr.org/2009/565.pdf, 3.2 243 | 244 | // Bunu kontrol ettik tamamen doğru çalışıyor. 245 | // gnark-crypto'dan kontrol ettik 246 | cyclotomic_square() { 247 | let t0 = this.c1.c1.square(); 248 | let t1 = this.c0.c0.square(); 249 | let t6 = this.c1.c1.add(this.c0.c0); 250 | t6 = t6.square(); 251 | t6 = t6.sub(t0); 252 | t6 = t6.sub(t1); 253 | let t2 = this.c0.c2.square(); 254 | let t3 = this.c1.c0.square(); 255 | let t7 = this.c0.c2.add(this.c1.c0); 256 | t7 = t7.square(); 257 | t7 = t7.sub(t2); 258 | t7 = t7.sub(t3); 259 | let t4 = this.c1.c2.square(); 260 | let t5 = this.c0.c1.square(); 261 | let t8 = this.c1.c2.add(this.c0.c1); 262 | t8 = t8.square(); 263 | t8 = t8.sub(t4); 264 | t8 = t8.sub(t5); 265 | t8 = t8.mul_by_nonresidue(); 266 | 267 | t0 = t0.mul_by_nonresidue(); 268 | t0 = t0.add(t1); 269 | t2 = t2.mul_by_nonresidue(); 270 | t2 = t2.add(t3); 271 | t4 = t4.mul_by_nonresidue(); 272 | t4 = t4.add(t5); 273 | 274 | let c0c0 = t0.sub(this.c0.c0); 275 | c0c0 = c0c0.double(); 276 | c0c0 = c0c0.add(t0); 277 | 278 | let c0c1 = t2.sub(this.c0.c1); 279 | c0c1 = c0c1.double(); 280 | c0c1 = c0c1.add(t2); 281 | 282 | let c0c2 = t4.sub(this.c0.c2); 283 | c0c2 = c0c2.double(); 284 | c0c2 = c0c2.add(t4); 285 | 286 | let c1c0 = t8.add(this.c1.c0); 287 | c1c0 = c1c0.double(); 288 | c1c0 = c1c0.add(t8); 289 | 290 | let c1c1 = t6.add(this.c1.c1); 291 | c1c1 = c1c1.double(); 292 | c1c1 = c1c1.add(t6); 293 | 294 | let c1c2 = t7.add(this.c1.c2); 295 | c1c2 = c1c2.double(); 296 | c1c1 = c1c2.add(t7); 297 | 298 | let c0 = new Fp6( 299 | c0c0, 300 | c0c1, 301 | c0c2 302 | ); 303 | 304 | let c1 = new Fp6( 305 | c1c0, 306 | c1c1, 307 | c1c2 308 | ); 309 | 310 | return new Fp12( 311 | c0, 312 | c1 313 | ); 314 | } 315 | 316 | // same with gnark 317 | n_square(n: any) { 318 | let x = new Fp12( 319 | this.c0, 320 | this.c1 321 | ); 322 | 323 | for (let i = 0; i < n; i++) { 324 | x = x.cyclotomic_square(); 325 | } 326 | 327 | return x; 328 | } 329 | 330 | // Checked: totally same with the gnark 331 | exponentiation() { 332 | let t3 = this.cyclotomic_square(); 333 | let t5 = t3.cyclotomic_square(); 334 | let result = t5.cyclotomic_square(); 335 | let t0 = result.cyclotomic_square(); 336 | let t2 = this.mul(t0); 337 | t0 = t2.mul(t3); 338 | let t1 = this.mul(t0); 339 | let t4 = result.mul(t2); 340 | let t6 = t2.cyclotomic_square(); 341 | t1 = t1.mul(t0); 342 | t0 = t1.mul(t3); 343 | t6 = t6.n_square(6); 344 | t5 = t5.mul(t6); 345 | t5 = t4.mul(t5); 346 | t5 = t5.n_square(7); 347 | t4 = t4.mul(t5); 348 | t4 = t4.n_square(8); 349 | t4 = t4.mul(t0); 350 | t3 = t3.mul(t4); 351 | t3 = t3.n_square(6); 352 | t2 = t2.mul(t3); 353 | t2 = t2.n_square(8); 354 | t2 = t0.mul(t2); 355 | t2 = t2.n_square(6); 356 | t2 = t0.mul(t2); 357 | t2 = t2.n_square(10); 358 | t1 = t1.mul(t2); 359 | t1 = t1.n_square(6); 360 | t0 = t0.mul(t1); 361 | result = result.mul(t0); 362 | 363 | return result; 364 | } 365 | 366 | mulBy034(c0: Fp2, c3: Fp2, c4: Fp2) { 367 | let a = this.c0.mulByE2(c0); 368 | 369 | let b = this.c1; 370 | // Check this line again! That might differ! 371 | b = b.mulBy01(c0, c3); 372 | 373 | c0 = c0.add(c3); 374 | let d = this.c0.add(this.c1); 375 | d = d.mulBy01(c0, c4); 376 | 377 | let z_c1 = a.add(b); 378 | z_c1 = z_c1.neg(); 379 | z_c1 = z_c1.add(d); 380 | 381 | let z_c0 = b.mul_by_nonresidue(); 382 | z_c0 = z_c0.add(a); 383 | 384 | return new Fp12( 385 | z_c0, 386 | z_c1 387 | ) 388 | } 389 | 390 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Licensed under the Apache License, Version 2.0 (the "License"); 190 | you may not use this file except in compliance with the License. 191 | You may obtain a copy of the License at 192 | 193 | http://www.apache.org/licenses/LICENSE-2.0 194 | 195 | Unless required by applicable law or agreed to in writing, software 196 | distributed under the License is distributed on an "AS IS" BASIS, 197 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 198 | See the License for the specific language governing permissions and 199 | limitations under the License. 200 | -------------------------------------------------------------------------------- /src/fq6.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Fq.ts uses {ForeignField, Field3} from {Gadgets} 3 | */ 4 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 5 | import Fq2 from "./fq2"; 6 | import Fq from "./fq"; 7 | 8 | // An element of Fq6, represented by c0 + c1 * v + c2 * v^2 9 | 10 | export default class Fq6{ 11 | c0: Fq2; 12 | c1: Fq2; 13 | c2: Fq2; 14 | 15 | constructor(c0: Fq2, c1: Fq2, c2: Fq2) { 16 | this.c0 = c0; 17 | this.c1 = c1; 18 | this.c2 = c2; 19 | } 20 | 21 | add(other: Fq6) { 22 | return new Fq6( 23 | this.c0.add(other.c0), 24 | this.c1.add(other.c1), 25 | this.c2.add(other.c2) 26 | ); 27 | } 28 | 29 | sub(other: Fq6) { 30 | return new Fq6( 31 | this.c0.sub(other.c0), 32 | this.c1.sub(other.c1), 33 | this.c2.sub(other.c2) 34 | ); 35 | } 36 | 37 | mul(other: Fq6) { 38 | let a_a = this.c0; 39 | let b_b = this.c1; 40 | let c_c = this.c2; 41 | a_a = a_a.mul(other.c0); 42 | b_b = b_b.mul(other.c1); // burada a_a.mul yapmışım bu yüzden hata çıktı. 43 | c_c = c_c.mul(other.c2); // burada a_a.mul yapmışım bu yüzden hata çıktı. 44 | 45 | let t1 = other.c1; 46 | t1 = t1.add(other.c2); 47 | 48 | let tmp = this.c1; 49 | tmp = tmp.add(this.c2); 50 | 51 | t1 = t1.mul(tmp); 52 | t1 = t1.sub(b_b); 53 | t1 = t1.sub(c_c); 54 | t1 = t1.mul_by_nonresidue(); 55 | t1 = t1.add(a_a); 56 | 57 | let t3 = other.c0; 58 | t3 = t3.add(other.c2); 59 | 60 | tmp = this.c0; 61 | tmp = tmp.add(this.c2); 62 | 63 | t3 = t3.mul(tmp); 64 | t3 = t3.sub(a_a); 65 | t3 = t3.add(b_b); 66 | t3 = t3.sub(c_c); 67 | 68 | let t2 = other.c0; 69 | t2 = t2.add(other.c1); 70 | 71 | tmp = this.c0; 72 | tmp = tmp.add(this.c1); 73 | 74 | t2 = t2.mul(tmp); 75 | t2 = t2.sub(a_a); 76 | t2 = t2.sub(b_b); 77 | c_c = c_c.mul_by_nonresidue(); 78 | t2 = t2.add(c_c); 79 | 80 | return new Fq6( 81 | t1, 82 | t2, 83 | t3 84 | ); 85 | } 86 | 87 | neg() { 88 | return new Fq6( 89 | this.c0.neg(), 90 | this.c1.neg(), 91 | this.c2.neg() 92 | ) 93 | } 94 | 95 | double() { 96 | return new Fq6( 97 | this.c0.double(), 98 | this.c1.double(), 99 | this.c2.double() 100 | ) 101 | } 102 | 103 | square() { 104 | // s0 = a^2 105 | let s0 = this.c0; 106 | s0 = s0.square(); 107 | 108 | // s1 = 2ab 109 | let ab = this.c0; 110 | ab = ab.mul(this.c1); 111 | let s1 = ab; 112 | s1 = s1.double(); 113 | 114 | // s2 = (a - b + c)^2 115 | let s2 = this.c0; 116 | s2 = s2.sub(this.c1); 117 | s2 = s2.add(this.c2); 118 | s2 = s2.square(); 119 | 120 | // bc 121 | let bc = this.c1; 122 | bc = bc.mul(this.c2); 123 | 124 | // s3 = 2bc 125 | let s3 = bc; 126 | s3 = bc.double(); 127 | 128 | // s4 = c^2 129 | let s4 = this.c2; 130 | s4 = s4.square(); 131 | 132 | // new c0 = 2bc.mul_by_xi + a^2 133 | let c0 = s3; 134 | c0 = c0.mul_by_nonresidue(); 135 | c0 = c0.add(s0); 136 | 137 | // new c1 = (c^2).mul_by_xi + 2ab 138 | let c1 = s4; 139 | c1 = c1.mul_by_nonresidue(); 140 | c1 = c1.add(s1); 141 | 142 | // new c2 = 2ab + (a - b + c)^2 + 2bc - a^2 - c^2 = b^2 + 2ac 143 | let c2 = s1; 144 | c2 = c2.add(s2); 145 | c2 = c2.add(s3); 146 | c2 = c2.sub(s0); 147 | c2 = c2.sub(s4); 148 | 149 | return new Fq6( 150 | c0, 151 | c1, 152 | c2 153 | ); 154 | } 155 | 156 | mul_by_nonresidue() { 157 | return new Fq6( 158 | this.c2.mul_by_nonresidue(), 159 | this.c0, 160 | this.c1 161 | ); 162 | } 163 | 164 | mul_by_1(c1: Fq2) { 165 | let b_b = this.c1; 166 | b_b = b_b.mul(c1); 167 | 168 | let t1 = c1; 169 | let tmp = this.c1; 170 | tmp = tmp.add(this.c2); 171 | 172 | t1 = t1.mul(tmp); 173 | t1 = t1.sub(b_b); 174 | t1 = t1.mul_by_nonresidue(); 175 | 176 | let t2 = c1; 177 | tmp = this.c0; 178 | tmp = tmp.add(this.c1); 179 | 180 | t2 = t2.mul(tmp); 181 | t2 = t2.sub(b_b); 182 | 183 | return new Fq6( 184 | t1, 185 | t2, 186 | b_b 187 | ); 188 | } 189 | 190 | mul_by_01(c0: Fq2, c1: Fq2) { 191 | let a_a = this.c0; 192 | let b_b = this.c1; 193 | a_a = a_a.mul(c0); 194 | b_b = b_b.mul(c1); 195 | 196 | let t1 = c1; 197 | let tmp = this.c1; 198 | tmp = tmp.add(this.c2); 199 | 200 | t1 = t1.mul(tmp); 201 | t1 = t1.sub(b_b); 202 | t1 = t1.mul_by_nonresidue(); 203 | t1 = t1.add(a_a); 204 | 205 | let t3 = c0; 206 | tmp = this.c0; 207 | tmp = tmp.add(this.c2); 208 | 209 | t3 = t3.mul(tmp); 210 | t3 = t3.sub(a_a); 211 | t3 = t3.add(b_b); 212 | 213 | let t2 = c0; 214 | t2 = t2.add(c1); 215 | 216 | tmp = this.c0; 217 | tmp = tmp.add(this.c1); 218 | 219 | t2 = t2.mul(tmp); 220 | t2 = t2.sub(a_a); 221 | t2 = t2.sub(b_b); 222 | 223 | return new Fq6( 224 | t1, 225 | t2, 226 | t3 227 | ); 228 | } 229 | 230 | invert() { 231 | let c0 = this.c2; 232 | c0 = c0.mul_by_nonresidue(); 233 | c0 = c0.mul(this.c1); 234 | c0 = c0.neg(); 235 | 236 | let c0s = this.c0; // c0 or this.c0 237 | c0s = c0s.square(); 238 | c0 = c0.add(c0s); 239 | 240 | let c1 = this.c2; 241 | c1 = c1.square(); 242 | c1 = c1.mul_by_nonresidue(); 243 | 244 | let c01 = this.c0; // c0 or this c0 245 | c01 = c01.mul(this.c1) // c1 or this c1 246 | c1 = c1.sub(c01); 247 | 248 | let c2 = this.c1; // or this.c1?? 249 | c2 = c2.square(); 250 | 251 | let c02 = this.c0; 252 | c02 = c02.mul(this.c2); 253 | c2 = c2.sub(c02); 254 | 255 | let tmp1 = this.c2; 256 | tmp1 = tmp1.mul(c1); 257 | let tmp2 = this.c1; 258 | tmp2 = tmp2.mul(c2); 259 | tmp1 = tmp1.add(tmp2); 260 | tmp1 = tmp1.mul_by_nonresidue(); 261 | tmp2 = this.c0; 262 | tmp2 = tmp2.mul(c0); 263 | tmp1 = tmp1.add(tmp2); 264 | 265 | let tmp = tmp1.invert(); 266 | c0 = tmp.mul(c0); 267 | c1 = tmp.mul(c1); 268 | c2 = tmp.mul(c2); 269 | 270 | return new Fq6( 271 | c0, 272 | c1, 273 | c2 274 | ); 275 | } 276 | 277 | // FROBENIUS_COEFF_FQ6_C1 Constants 278 | // fq2 0 279 | // 1 280 | // 0 281 | // fq2 1 282 | // 21575463638280843010398324269430826099269044274347216827212613867836435027261 283 | // 10307601595873709700152284273816112264069230130616436755625194854815875713954 284 | // fq2 2 285 | // 21888242871839275220042445260109153167277707414472061641714758635765020556616 286 | // 0 287 | // fq2 3 288 | // 3772000881919853776433695186713858239009073593817195771773381919316419345261 289 | // 2236595495967245188281701248203181795121068902605861227855261137820944008926 290 | // fq2 4 291 | // 2203960485148121921418603742825762020974279258880205651966 292 | // 0 293 | // fq2 5 294 | // 18429021223477853657660792034369865839114504446431234726392080002137598044644 295 | // 9344045779998320333812420223237981029506012124075525679208581902008406485703 296 | 297 | frobenius_map(power: bigint) { 298 | let c0 = this.c0.frobenius_map(power); 299 | let c1 = this.c1.frobenius_map(power); 300 | let c2 = this.c2.frobenius_map(power); 301 | 302 | if (power %6n == 0n) { 303 | return new Fq6( 304 | c0, 305 | c1.mul( 306 | new Fq2( 307 | new Fq(1n), 308 | new Fq(0n) 309 | ) 310 | ), 311 | c2.mul( 312 | new Fq2( 313 | new Fq(1n), 314 | new Fq(0n) 315 | ) 316 | ) 317 | ); 318 | } else if (power %6n == 1n) { 319 | return new Fq6( 320 | c0, 321 | c1.mul( 322 | new Fq2( 323 | new Fq(21575463638280843010398324269430826099269044274347216827212613867836435027261n), 324 | new Fq(10307601595873709700152284273816112264069230130616436755625194854815875713954n) 325 | ) 326 | ), 327 | c2.mul( 328 | new Fq2( 329 | new Fq(2581911344467009335267311115468803099551665605076196740867805258568234346338n), 330 | new Fq(19937756971775647987995932169929341994314640652964949448313374472400716661030n) 331 | ) 332 | ) 333 | ); 334 | } else if (power %6n == 2n) { 335 | return new Fq6( 336 | c0, 337 | c1.mul( 338 | new Fq2( 339 | new Fq(21888242871839275220042445260109153167277707414472061641714758635765020556616n), 340 | new Fq(0n) 341 | ) 342 | ), 343 | c2.mul( 344 | new Fq2( 345 | new Fq(2203960485148121921418603742825762020974279258880205651966n), 346 | new Fq(0n) 347 | ) 348 | ) 349 | ); 350 | } else if (power %6n == 3n) { 351 | return new Fq6( 352 | c0, 353 | c1.mul( 354 | new Fq2( 355 | new Fq(3772000881919853776433695186713858239009073593817195771773381919316419345261n), 356 | new Fq(2236595495967245188281701248203181795121068902605861227855261137820944008926n) 357 | ) 358 | ), 359 | c2.mul( 360 | new Fq2( 361 | new Fq(5324479202449903542726783395506214481928257762400643279780343368557297135718n), 362 | new Fq(16208900380737693084919495127334387981393726419856888799917914180988844123039n) 363 | ) 364 | ) 365 | ); 366 | } else if (power %6n == 4n) { 367 | return new Fq6( 368 | c0, 369 | c1.mul( 370 | new Fq2( 371 | new Fq(2203960485148121921418603742825762020974279258880205651966n), 372 | new Fq(0n) 373 | ) 374 | ), 375 | c2.mul( 376 | new Fq2( 377 | new Fq(21888242871839275220042445260109153167277707414472061641714758635765020556616n), 378 | new Fq(0n) 379 | ) 380 | ) 381 | ); 382 | } else { 383 | return new Fq6( 384 | c0, 385 | c1.mul( 386 | new Fq2( 387 | new Fq(18429021223477853657660792034369865839114504446431234726392080002137598044644n), 388 | new Fq(9344045779998320333812420223237981029506012124075525679208581902008406485703n) 389 | ) 390 | ), 391 | c2.mul( 392 | new Fq2( 393 | new Fq(13981852324922362344252311234282257507216387789820983642040889267519694726527n), 394 | new Fq(7629828391165209371577384193250820201684255241773809077146787135900891633097n) 395 | ) 396 | ) 397 | ); 398 | } 399 | } 400 | 401 | // need test 402 | static one() { 403 | 404 | } 405 | 406 | static zero() { 407 | 408 | } 409 | 410 | 411 | } 412 | 413 | -------------------------------------------------------------------------------- /src/pairing.ts: -------------------------------------------------------------------------------- 1 | import Fp12 from './fp12'; 2 | import Fp6 from './fp6'; 3 | import Fp2 from './fp2'; 4 | import G2Group from './g2'; 5 | import { NAF_DIGIT } from './const'; 6 | import { assertPreconditionInvariants } from 'o1js/dist/node/lib/precondition'; 7 | import G1Group from './g1'; 8 | 9 | class LineEval { 10 | L: Fp12 11 | T: G2Group 12 | 13 | constructor(L: Fp12, T:G2Group) { 14 | this.L = L; 15 | this.T = T; 16 | } 17 | } 18 | 19 | export default class Pairing{ 20 | 21 | static line_eval: [Fp12, G2Group]; 22 | 23 | // Algorithm 26 from: https://eprint.iacr.org/2010/354.pdf 24 | static line_function_double_point(q: G2Group, p: G1Group) { 25 | let tmp0 = q.x.square(); 26 | let tmp1 = q.y.square(); 27 | let tmp2 = tmp1.square(); 28 | let x = tmp1.add(q.x); 29 | x = x.square(); 30 | x = x.sub(tmp0); 31 | let tmp3 = x.sub(tmp2); 32 | tmp3 = tmp3.double(); 33 | let tmp4 = tmp0.add(tmp0.double()); 34 | let tmp6 = q.x.add(tmp4); 35 | let tmp5 = tmp4.square(); 36 | let X_T = tmp5.sub(tmp3.double()); 37 | let Z_T = q.y.add(q.z); 38 | Z_T = Z_T.square(); 39 | Z_T = Z_T.sub(tmp1); 40 | Z_T = Z_T.sub(q.z.square()); 41 | let Y_T = tmp3.sub(X_T); 42 | Y_T = Y_T.mul(tmp4); 43 | let tmp2_8 = tmp2.double(); 44 | tmp2_8 = tmp2_8.double(); 45 | tmp2_8 = tmp2_8.double(); 46 | Y_T = Y_T.sub(tmp2_8); 47 | //tmp3 = tmp4.mul(q.z.double()); // Burası double değil square olacak. 48 | tmp3 = tmp4.mul(q.z.square()); 49 | tmp3 = tmp3.double(); 50 | tmp3 = tmp3.neg(); 51 | tmp3 = tmp3.mul_by_b0(p.x); 52 | tmp6 = tmp6.square(); 53 | tmp6 = tmp6.sub(tmp0); 54 | tmp6 = tmp6.sub(tmp5); 55 | let tmp1_4 = tmp1.double(); 56 | tmp1_4 = tmp1_4.double(); 57 | tmp6 = tmp6.sub(tmp1_4); 58 | tmp0 = Z_T.mul(q.z.square()); 59 | tmp0 = tmp0.double(); 60 | tmp0 = tmp0.mul_by_b0(p.y); 61 | 62 | let a0 = new Fp6( 63 | tmp0, 64 | Fp2.zero(), 65 | Fp2.zero(), 66 | ); 67 | 68 | let a1 = new Fp6( 69 | tmp3, 70 | tmp6, 71 | Fp2.zero(), 72 | ); 73 | 74 | let l = new Fp12( 75 | a0, 76 | a1, 77 | ); 78 | 79 | let T = G2Group.to_affine(new G2Group(X_T, Y_T), Z_T); 80 | 81 | return new LineEval( 82 | l, 83 | T 84 | ); 85 | } 86 | 87 | // Algorithm 27 from: https://eprint.iacr.org/2010/354.pdf 88 | static line_function_add_point(q: G2Group, r: G2Group, p: G1Group) { 89 | let t0 = q.x.mul(r.z.square()); 90 | let t1 = q.y.add(r.z); 91 | t1 = t1.square(); 92 | t1 = t1.sub(q.y.square()); 93 | t1 = t1.sub(r.z.square()); 94 | t1 = t1.mul(r.z.square()); 95 | let t2 = t0.sub(r.x); 96 | let t3 = t2.square(); 97 | let t4 = t3.double(); 98 | t4 = t4.double(); 99 | let t5 = t4.mul(t2); 100 | let t6 = t1.sub(r.y.double()); 101 | let t9 = t6.mul(q.x); 102 | let t7 = r.x.mul(t4); 103 | let X_T = t6.square(); 104 | X_T = X_T.sub(t5); 105 | X_T = X_T.sub(t7.double()); 106 | let Z_T = r.z.add(t2); 107 | Z_T = Z_T.square(); 108 | Z_T = Z_T.sub(r.z.square()); 109 | Z_T = Z_T.sub(t3); 110 | let t10 = q.y.add(Z_T); 111 | let t8 = t7.sub(X_T); 112 | t8 = t8.mul(t6); 113 | t0 = r.y.mul(t5); 114 | t0 = t0.double(); 115 | let Y_T = t8.sub(t0); 116 | t10 = t10.square(); 117 | t10 = t10.sub(q.y.square()); 118 | t10 = t10.sub(Z_T.square()); 119 | t9 = t9.double(); 120 | t9 = t9.sub(t10); 121 | t10 = Z_T.mul_by_b0(p.y); 122 | t10 = t10.double(); 123 | t6 = t6.neg(); 124 | t1 = t6.mul_by_b0(p.x); 125 | t1 = t1.double(); 126 | 127 | let l0 = new Fp6( 128 | t10, 129 | Fp2.zero(), 130 | Fp2.zero(), 131 | ); 132 | 133 | let l1 = new Fp6( 134 | t1, 135 | t9, 136 | Fp2.zero(), 137 | ); 138 | 139 | let l = new Fp12( 140 | l0, 141 | l1, 142 | ); 143 | 144 | let T = G2Group.to_affine(new G2Group(X_T, Y_T), Z_T); 145 | 146 | return new LineEval( 147 | l, 148 | T 149 | ); 150 | } 151 | 152 | static addition_step_halo2_curve(q: G2Group, r: G2Group) { 153 | let zsquared = r.z; 154 | zsquared = r.z.square(); 155 | 156 | let ysquared = q.y; 157 | ysquared = ysquared.square(); 158 | 159 | let t0 = zsquared; 160 | t0 = t0.mul(q.x); 161 | 162 | let t1 = q.y; 163 | t1 = t1.add(r.z); 164 | t1 = t1.square(); 165 | t1 = t1.sub(ysquared); 166 | t1 = t1.sub(zsquared); 167 | t1 = t1.mul(zsquared); 168 | 169 | let t2 = t0; 170 | t2 = t2.sub(r.x); 171 | 172 | let t3 = t2; 173 | t3 = t3.square(); 174 | 175 | let t4 = t3; 176 | t4 = t4.double(); 177 | t4 = t4.double(); 178 | 179 | let t5 = t4; 180 | t5 = t5.mul(t2); 181 | 182 | let t6 = t1; 183 | t6 = t6.sub(r.y); 184 | t6 = t6.sub(r.y); 185 | 186 | let t9 = t6; 187 | t9 = t9.mul(q.x); 188 | 189 | let t7 = t4; 190 | t7 = t7.mul(r.x); 191 | 192 | r.x = t6; 193 | r.x = r.x.square(); 194 | r.x = r.x.sub(t5); 195 | r.x = r.x.sub(t6); 196 | r.x = r.x.sub(t7); 197 | 198 | r.z = r.z.add(t2); 199 | r.z = r.z.square(); 200 | r.z = r.z.sub(zsquared); 201 | r.z = r.z.sub(t3); 202 | 203 | let t10 = q.y; 204 | t10 = t10.add(r.z); 205 | 206 | let t8 = t7; 207 | t8 = t8.sub(r.x); 208 | t8 = t8.mul(t6); 209 | 210 | t0 = r.y; 211 | t0 = t0.mul(t5); 212 | t0 = t0.double(); 213 | 214 | r.y = t8; 215 | r.y = r.y.sub(t0); 216 | 217 | t10 = t10.square(); 218 | t10 = t10.sub(ysquared); 219 | 220 | let ztsquared = r.z; 221 | ztsquared = ztsquared.square(); 222 | 223 | t10 = t10.sub(ztsquared); 224 | 225 | t9 = t9.double(); 226 | t9 = t9.sub(t10); 227 | 228 | t10 = r.z; 229 | t10 = t10.double(); 230 | 231 | t6 = t6.neg(); 232 | 233 | t1 = t6; 234 | t1 = t1.double(); 235 | 236 | return new Fp6( 237 | t10, 238 | t1, 239 | t9 240 | ); 241 | } 242 | 243 | /*static final_exponentiation(z: Fp12) { 244 | // Easy part 245 | 246 | let result = z; 247 | let t0 = z.conjugate(); 248 | result = result.invert(); 249 | t0 = t0.mul(result); 250 | result = t0.frobenius_square(); 251 | result = result.mul(t0); 252 | 253 | // Hard part 254 | // https://eprint.iacr.org/2015/192.pdf 255 | 256 | t0 = result.exponentiation(); 257 | t0 = t0.conjugate(); 258 | t0 = t0.cyclotomic_square(); 259 | let t2 = t0.exponentiation(); 260 | t2 = t2.conjugate(); 261 | let t1 = t2.cyclotomic_square(); 262 | t2 = t2.mul(t1); 263 | t2 = t2.mul(result); 264 | t1 = t2.exponentiation(); 265 | t1 = t1.cyclotomic_square(); 266 | t1 = t1.mul(t2); 267 | t1 = t1.conjugate(); 268 | let t3 = t1.conjugate(); 269 | t1 = t0.cyclotomic_square(); 270 | t1 = t1.mul(result); 271 | t1 = t1.conjugate(); 272 | t1 = t1.mul(t3); 273 | t0 = t0.mul(t1); 274 | t2 = t2.mul(t1); 275 | t3 = t1.frobenius_square(); 276 | t2 = t2.mul(t3); 277 | t3 = result.conjugate(); 278 | t3 = t3.mul(t0); 279 | t1 = t3.frobenius_cube(); 280 | t2 = t2.mul(t1); 281 | t1 = t0.frobenius(); 282 | t1 = t1.mul(t2); 283 | 284 | return t1; 285 | }*/ 286 | 287 | // FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ 288 | // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r 289 | // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r 290 | // where s is the cofactor 2x₀(6x₀²+3x₀+1) 291 | // Totally same with gnark 292 | 293 | static final_exponentiation_gnark(z: Fp12) { 294 | // Easy part 295 | 296 | let result = z; 297 | let t0 = z.conjugate(); 298 | result = result.invert(); 299 | t0 = t0.mul(result); 300 | result = t0.frobenius_square(); 301 | result = result.mul(t0); 302 | 303 | // Hard part 304 | // https://eprint.iacr.org/2015/192.pdf 305 | 306 | t0 = result.exponentiation(); 307 | t0 = t0.conjugate(); 308 | t0 = t0.cyclotomic_square(); 309 | let t1 = t0.cyclotomic_square(); 310 | t1 = t0.mul(t1); 311 | let t2 = t1.exponentiation(); 312 | t2 = t2.conjugate(); 313 | let t3 = t1.conjugate(); 314 | t1 = t2.mul(t3); 315 | t3 = t2.cyclotomic_square(); 316 | let t4 = t3.exponentiation(); 317 | t4 = t1.mul(t4); 318 | t3 = t0.mul(t4); 319 | t0 = t2.mul(t4); 320 | t0 = t0.mul(result); 321 | t2 = t3.frobenius(); 322 | t0 = t2.mul(t0); 323 | t2 = t4.frobenius_square(); 324 | t0 = t2.mul(t0); 325 | t2 = result.conjugate(); 326 | t2 = t2.mul(t3); 327 | t2 = t2.frobenius_cube(); 328 | t0 = t2.mul(t0); 329 | 330 | return t0; 331 | } 332 | 333 | /*static final_exponentiation_new(f: Fp12) { 334 | let f1 = f.conjugate(); 335 | let f2 = f.invert(); 336 | f = f1.mul(f2); 337 | f = f.frobenius_square().mul(f); // mul f var mı yok mu? 338 | //let ft1 = f.exponentiation(); 339 | //let ft2 = f.exponentiation(); 340 | //let ft3 341 | let fp1 = f.frobenius(); 342 | let fp2 = f.frobenius_square(); 343 | let fp3 = f.frobenius_cube(); 344 | let y0 = fp1.mul(fp2).mul(fp3); 345 | let y1 = f1; 346 | let y2 = 347 | 348 | }*/ 349 | 350 | static miller_loop(Q: G2Group, P:G1Group) { 351 | let ate_loop_count = 29793968203157093288; 352 | let log_ate_loop_count = 63; 353 | let T = Q; 354 | let f = Fp12.one(); 355 | 356 | for (let i = 0; i < 64; i++) { 357 | let line_evaluated = Pairing.line_function_double_point(T, P); 358 | f = f.square(); 359 | f = f.mul(line_evaluated.L); 360 | T = line_evaluated.T; 361 | 362 | if (NAF_DIGIT[i] == 2) { 363 | let Q_NEG = Q.neg(); 364 | let line_evaluated = Pairing.line_function_add_point(T, Q_NEG, P); 365 | f = f.mul(line_evaluated.L); 366 | T = line_evaluated.T; 367 | } else if (NAF_DIGIT[i] == 1) { 368 | let line_evaluated = Pairing.line_function_add_point(T, Q, P); 369 | f = f.mul(line_evaluated.L); 370 | T = line_evaluated.T; 371 | } 372 | } 373 | 374 | let q1x = Q.x.conjugate(); 375 | let q1y = Q.y.conjugate(); 376 | q1x = q1x.mul_by_non_residue_1_power_2(); 377 | q1y = q1y.mul_by_non_residue_1_power_3(); 378 | //let Q1 = G2Group.fromAffine(q1x, q1y); 379 | let Q1 = new G2Group(q1x, q1y); 380 | 381 | // Q2 <- pi_p_square(Q); 382 | let q2x = Q.x.mul_by_non_residue_2_power_2(); 383 | let q2y = Q.y.mul_by_non_residue_2_power_3(); 384 | q2y = q2y.neg(); 385 | // Q2 is negated above to use directly in the line_function 386 | //let Q2 = G2Group.fromAffine(q2x, q2y); 387 | let Q2 = new G2Group(q2x, q2y); 388 | 389 | // Line eval with Q1 390 | let line_evaluated = Pairing.line_function_add_point(T, Q1, P); 391 | f = f.mul(line_evaluated.L); 392 | T = line_evaluated.T; 393 | 394 | // Line eval with Q2 395 | line_evaluated = Pairing.line_function_add_point(T, Q2, P); 396 | f = f.mul(line_evaluated.L); 397 | return f; 398 | } 399 | 400 | static new_miller_loop(Q: G2Group, P:G1Group) { 401 | if(Q.isZero() || P.isZero()) { 402 | return Fp12.one(); 403 | } 404 | 405 | let R = Q; 406 | let f = Fp12.one(); 407 | 408 | for(let i = 63; i > -1; i--) { 409 | let line_evaluated = this.line_function_double_point(R, P); 410 | f = f.mul(f).mul(line_evaluated.L); 411 | R = line_evaluated.T; 412 | if (29793968203157093288 & (2**i)) { 413 | let line_evaluated = this.line_function_add_point(R, Q, P); 414 | f = f.mul(line_evaluated.L); 415 | R = R.add(Q); 416 | } 417 | } 418 | 419 | let q1x = Q.x.conjugate(); 420 | let q1y = Q.y.conjugate(); 421 | q1x = q1x.mul_by_non_residue_1_power_2(); 422 | q1y = q1y.mul_by_non_residue_1_power_3(); 423 | //let Q1 = G2Group.fromAffine(q1x, q1y); 424 | let Q1 = new G2Group(q1x, q1y); 425 | 426 | // Q2 <- pi_p_square(Q); 427 | let q2x = Q.x.mul_by_non_residue_2_power_2(); 428 | let q2y = Q.y.mul_by_non_residue_2_power_3(); 429 | q2y = q2y.neg(); 430 | // Q2 is negated above to use directly in the line_function 431 | //let Q2 = G2Group.fromAffine(q2x, q2y); 432 | let Q2 = new G2Group(q2x, q2y); 433 | 434 | // Line eval with Q1 435 | let line_evaluated = Pairing.line_function_add_point(R, Q1, P); 436 | f = f.mul(line_evaluated.L); 437 | R = line_evaluated.T; 438 | 439 | // Line eval with Q2 440 | line_evaluated = Pairing.line_function_add_point(R, Q2, P); 441 | f = f.mul(line_evaluated.L); 442 | return f; 443 | } 444 | 445 | static pair(Q: G2Group, P: G1Group) { 446 | let res = Pairing.miller_loop(Q, P); 447 | res = this.final_exponentiation_gnark(res); 448 | //res = this.final_exponentiation(res); 449 | return res; 450 | } 451 | 452 | // new_miller_loop_test: 453 | // 4947317154039212424161228730094156662200671128105684755547588065693438310968 454 | // 4498429767852986861166227158110591543825586580979294626332366971473013976019 455 | 456 | // miller_loop_test: 457 | // 4947317154039212424161228730094156662200671128105684755547588065693438310968 458 | // 4498429767852986861166227158110591543825586580979294626332366971473013976019 459 | 460 | // Bu şu anlama geliyor ki new_miller_loop ile miller_loop aynı ve bazı kısımları doğru çalışıyor. Looplu olanları. 461 | 462 | // miller_loop'ta bir sıkıntı olduğunu düşünmüyorum. 463 | // fakat, final_exp'te bir sıkıntı var gibi çünkü sürekli (1, 1, 0, 0) -> buna bile (1, 0, 0) döndürdü. 464 | 465 | } -------------------------------------------------------------------------------- /src/fq12.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Fq.ts uses {ForeignField, Field3} from {Gadgets} 3 | */ 4 | import { ForeignField, Field3 } from "o1js/dist/node/lib/gadgets/foreign-field"; 5 | import Fq6 from './fq6'; 6 | import Fq2 from "./fq2"; 7 | import Fq from "./fq"; 8 | import Pairing from "./pairing_new"; 9 | 10 | /// An element of Fq2, represented by c0 + c1 * w; where u^2 = -1. 11 | 12 | export default class Fq12{ 13 | c0: Fq6; 14 | c1: Fq6; 15 | 16 | constructor(c0: Fq6, c1: Fq6) { 17 | this.c0 = c0; 18 | this.c1 = c1; 19 | } 20 | 21 | add(other: Fq12) { 22 | return new Fq12( 23 | this.c0.add(other.c0), 24 | this.c1.add(other.c1), 25 | ); 26 | } 27 | 28 | sub(other: Fq12) { 29 | return new Fq12( 30 | this.c0.sub(other.c0), 31 | this.c1.sub(other.c1), 32 | ); 33 | } 34 | 35 | neg() { 36 | return new Fq12( 37 | this.c0.neg(), 38 | this.c1.neg() 39 | ) 40 | } 41 | 42 | double() { 43 | return new Fq12( 44 | this.c0.double(), 45 | this.c1.double() 46 | ) 47 | } 48 | 49 | mul(other: Fq12) { 50 | let t0 = this.c0.mul(other.c0); 51 | let t1 = this.c1.mul(other.c1); 52 | let t2 = other.c0.add(other.c1); 53 | 54 | let c1 = this.c1.add(this.c0); 55 | c1 = c1.mul(t2); 56 | c1 = c1.sub(t0); 57 | c1 = c1.sub(t1); 58 | 59 | t1 = t1.mul_by_nonresidue(); 60 | let c0 = t0.add(t1); 61 | 62 | return new Fq12( 63 | c0, 64 | c1 65 | ); 66 | } 67 | 68 | square() { 69 | let ab = this.c0.mul(this.c1); 70 | 71 | let c0c1 = this.c0.add(this.c1); 72 | 73 | let c0 = this.c1; 74 | c0 = c0.mul_by_nonresidue(); 75 | c0 = c0.add(this.c0); 76 | c0 = c0.mul(c0c1); 77 | c0 = c0.sub(ab); 78 | 79 | let c1 = ab; 80 | c1 = c1.add(ab); 81 | ab = ab.mul_by_nonresidue(); 82 | c0 = c0.sub(ab); 83 | 84 | return new Fq12( 85 | c0, 86 | c1 87 | ); 88 | } 89 | 90 | conjugate() { 91 | return new Fq12( 92 | this.c0, 93 | this.c1.neg() 94 | ) 95 | } 96 | 97 | mul_by_014(c0: Fq2, c1: Fq2, c4: Fq2) { 98 | let aa = this.c0; 99 | aa = aa.mul_by_01(c0, c1); 100 | let bb = this.c1; 101 | bb = bb.mul_by_1(c4); 102 | let o = c1.add(c4); 103 | 104 | let c1_new = this.c1.add(this.c0); // check this 105 | c1_new = c1_new.mul_by_01(c0, o); 106 | c1_new = c1_new.sub(aa); 107 | c1_new = c1_new.sub(bb); 108 | 109 | let c0_new = bb; 110 | c0_new = c0_new.mul_by_nonresidue(); 111 | c0_new = c0_new.add(aa); 112 | 113 | return new Fq12( 114 | c0_new, 115 | c1_new 116 | ); 117 | } 118 | 119 | mul_by_034(c0: Fq2, c3: Fq2, c4: Fq2) { 120 | let t0 = new Fq6( 121 | this.c0.c0.mul(c0), 122 | this.c0.c1.mul(c0), 123 | this.c0.c2.mul(c0) 124 | ); 125 | 126 | let t1 = this.c1; 127 | t1 = t1.mul_by_01(c3, c4); 128 | let o = c0.add(c3); 129 | let t2 = this.c0.add(this.c1); 130 | t2 = t2.mul_by_01(o, c4); 131 | t2 = t2.sub(t0); 132 | 133 | let c1_new = t2.sub(t1); 134 | t1 = t1.mul_by_nonresidue(); 135 | let c0_new = t0.add(t1); 136 | 137 | return new Fq12( 138 | c0_new, 139 | c1_new 140 | ); 141 | } 142 | 143 | invert() { 144 | let c0s = this.c0; 145 | c0s = c0s.square(); 146 | 147 | let c1s = this.c1; 148 | c1s = c1s.square(); 149 | c1s = c1s.mul_by_nonresidue(); 150 | c0s = c0s.sub(c1s); 151 | 152 | let t = c0s.invert(); 153 | let c0 = t.mul(this.c0); // check this 154 | let c1 = t.mul(this.c1); // check this 155 | c1 = c1.neg(); 156 | 157 | return new Fq12( 158 | c0, 159 | c1 160 | ); 161 | 162 | } 163 | 164 | // instead of transforming 165 | // let's return c0 of Fq6 and c1 of Fq6 166 | // we can change Fq2.zero() later 167 | fp4_square(a0: Fq2, a1: Fq2) { 168 | let t0 = a0.square(); 169 | let t1 = a1.square(); 170 | let t2 = t1; 171 | t2 = t2.mul_by_nonresidue(); 172 | let c0 = t2.add(t0); 173 | t2 = a0.add(a1); 174 | t2 = t2.square(); 175 | t2 = t2.sub(t0); 176 | let c1 = t2.sub(t1); 177 | 178 | return new Fq6( 179 | c0, 180 | c1, 181 | Fq2.zero() 182 | ); 183 | } 184 | 185 | cyclotomic_square() { 186 | let t3_t4 = this.fp4_square(this.c0.c0, this.c1.c1); 187 | let t3 = t3_t4.c0; 188 | let t4 = t3_t4.c1; 189 | 190 | let t2 = t3.sub(this.c0.c0); 191 | t2 = t2.double(); 192 | 193 | let new_c0_c0 = t2.add(t3); 194 | 195 | t2 = t4.add(this.c1.c1); 196 | t2 = t2.double(); 197 | 198 | let new_c1_c1 = t2.add(t4); 199 | 200 | let new_t3_t4 = this.fp4_square(this.c1.c0, this.c0.c2); 201 | 202 | t3 = new_t3_t4.c0; // Check this 203 | t4 = new_t3_t4.c1; // Check this 204 | 205 | let t5_t6 = this.fp4_square(this.c0.c1, this.c1.c2); 206 | 207 | let t5 = t5_t6.c0; 208 | let t6 = t5_t6.c1; 209 | 210 | t2 = t3.sub(this.c0.c1); 211 | t2 = t2.double(); 212 | 213 | let new_c0_c1 = t2.add(t3); 214 | t2 = t4.add(this.c1.c2); 215 | t2 = t2.double(); 216 | 217 | let new_c1_c2 = t2.add(t4); 218 | t3 = t6; 219 | t3 = t3.mul_by_nonresidue(); 220 | t2 = t3.add(this.c1.c0); 221 | t2 = t2.double(); 222 | let new_c1_c0 = t2.add(t3); 223 | t2 = t5.sub(this.c0.c2); 224 | t2 = t2.double(); 225 | let new_c0_c2 = t2.add(t5); 226 | 227 | return new Fq12( 228 | new Fq6( 229 | new_c0_c0, 230 | new_c0_c1, 231 | new_c0_c2 232 | ), 233 | new Fq6( 234 | new_c1_c0, 235 | new_c1_c1, 236 | new_c1_c2 237 | ) 238 | ); 239 | } 240 | 241 | // be sure power is provable 242 | frobenius_map(power: bigint) { 243 | let c0 = this.c0.frobenius_map(power); 244 | let c1 = this.c1.frobenius_map(power); 245 | 246 | if (power %12n == 0n) { 247 | let frobenius_coeff_fq12_c1 = new Fq2( 248 | new Fq(1n), 249 | new Fq(0n) 250 | ); 251 | 252 | return new Fq12( 253 | c0, 254 | new Fq6( 255 | c1.c0.mul(frobenius_coeff_fq12_c1), 256 | c1.c1.mul(frobenius_coeff_fq12_c1), 257 | c1.c2.mul(frobenius_coeff_fq12_c1) 258 | ) 259 | ); 260 | } else if (power %12n == 1n) { 261 | let frobenius_coeff_fq12_c1 = new Fq2( 262 | new Fq(8376118865763821496583973867626364092589906065868298776909617916018768340080n), 263 | new Fq(16469823323077808223889137241176536799009286646108169935659301613961712198316n) 264 | ); 265 | 266 | return new Fq12( 267 | c0, 268 | new Fq6( 269 | c1.c0.mul(frobenius_coeff_fq12_c1), 270 | c1.c1.mul(frobenius_coeff_fq12_c1), 271 | c1.c2.mul(frobenius_coeff_fq12_c1) 272 | ) 273 | ); 274 | } 275 | 276 | else if (power %12n == 2n) { 277 | let frobenius_coeff_fq12_c1 = new Fq2( 278 | new Fq(21888242871839275220042445260109153167277707414472061641714758635765020556617n), 279 | new Fq(0n) 280 | ); 281 | 282 | return new Fq12( 283 | c0, 284 | new Fq6( 285 | c1.c0.mul(frobenius_coeff_fq12_c1), 286 | c1.c1.mul(frobenius_coeff_fq12_c1), 287 | c1.c2.mul(frobenius_coeff_fq12_c1) 288 | ) 289 | ); 290 | } 291 | 292 | else if (power %12n == 3n) { 293 | let frobenius_coeff_fq12_c1 = new Fq2( 294 | new Fq(11697423496358154304825782922584725312912383441159505038794027105778954184319n), 295 | new Fq(303847389135065887422783454877609941456349188919719272345083954437860409601n) 296 | ); 297 | 298 | return new Fq12( 299 | c0, 300 | new Fq6( 301 | c1.c0.mul(frobenius_coeff_fq12_c1), 302 | c1.c1.mul(frobenius_coeff_fq12_c1), 303 | c1.c2.mul(frobenius_coeff_fq12_c1) 304 | ) 305 | ); 306 | } 307 | 308 | else if (power %12n == 4n) { 309 | let frobenius_coeff_fq12_c1 = new Fq2( 310 | new Fq(21888242871839275220042445260109153167277707414472061641714758635765020556616n), 311 | new Fq(0n) 312 | ); 313 | 314 | return new Fq12( 315 | c0, 316 | new Fq6( 317 | c1.c0.mul(frobenius_coeff_fq12_c1), 318 | c1.c1.mul(frobenius_coeff_fq12_c1), 319 | c1.c2.mul(frobenius_coeff_fq12_c1) 320 | ) 321 | ); 322 | } 323 | 324 | else if (power %12n == 5n) { 325 | let frobenius_coeff_fq12_c1 = new Fq2( 326 | new Fq(3321304630594332808241809054958361220322477375291206261884409189760185844239n), 327 | new Fq(5722266937896532885780051958958348231143373700109372999374820235121374419868n) 328 | ); 329 | 330 | return new Fq12( 331 | c0, 332 | new Fq6( 333 | c1.c0.mul(frobenius_coeff_fq12_c1), 334 | c1.c1.mul(frobenius_coeff_fq12_c1), 335 | c1.c2.mul(frobenius_coeff_fq12_c1) 336 | ) 337 | ); 338 | } 339 | 340 | else if (power %12n == 6n) { 341 | let frobenius_coeff_fq12_c1 = new Fq2( 342 | new Fq(21888242871839275222246405745257275088696311157297823662689037894645226208582n), 343 | new Fq(0n) 344 | ); 345 | 346 | return new Fq12( 347 | c0, 348 | new Fq6( 349 | c1.c0.mul(frobenius_coeff_fq12_c1), 350 | c1.c1.mul(frobenius_coeff_fq12_c1), 351 | c1.c2.mul(frobenius_coeff_fq12_c1) 352 | ) 353 | ); 354 | } 355 | 356 | else if (power %12n == 7n) { 357 | let frobenius_coeff_fq12_c1 = new Fq2( 358 | new Fq(13512124006075453725662431877630910996106405091429524885779419978626457868503n), 359 | new Fq(5418419548761466998357268504080738289687024511189653727029736280683514010267n) 360 | ); 361 | 362 | return new Fq12( 363 | c0, 364 | new Fq6( 365 | c1.c0.mul(frobenius_coeff_fq12_c1), 366 | c1.c1.mul(frobenius_coeff_fq12_c1), 367 | c1.c2.mul(frobenius_coeff_fq12_c1) 368 | ) 369 | ); 370 | } 371 | 372 | else if (power %12n == 8n) { 373 | let frobenius_coeff_fq12_c1 = new Fq2( 374 | new Fq(2203960485148121921418603742825762020974279258880205651966n), 375 | new Fq(0n) 376 | ); 377 | 378 | return new Fq12( 379 | c0, 380 | new Fq6( 381 | c1.c0.mul(frobenius_coeff_fq12_c1), 382 | c1.c1.mul(frobenius_coeff_fq12_c1), 383 | c1.c2.mul(frobenius_coeff_fq12_c1) 384 | ) 385 | ); 386 | } 387 | 388 | else if (power %12n == 9n) { 389 | let frobenius_coeff_fq12_c1 = new Fq2( 390 | new Fq(10190819375481120917420622822672549775783927716138318623895010788866272024264n), 391 | new Fq(21584395482704209334823622290379665147239961968378104390343953940207365798982n) 392 | ); 393 | 394 | return new Fq12( 395 | c0, 396 | new Fq6( 397 | c1.c0.mul(frobenius_coeff_fq12_c1), 398 | c1.c1.mul(frobenius_coeff_fq12_c1), 399 | c1.c2.mul(frobenius_coeff_fq12_c1) 400 | ) 401 | ); 402 | } 403 | 404 | else if (power %12n == 10n) { 405 | let frobenius_coeff_fq12_c1 = new Fq2( 406 | new Fq(2203960485148121921418603742825762020974279258880205651967n), 407 | new Fq(0n) 408 | ); 409 | 410 | return new Fq12( 411 | c0, 412 | new Fq6( 413 | c1.c0.mul(frobenius_coeff_fq12_c1), 414 | c1.c1.mul(frobenius_coeff_fq12_c1), 415 | c1.c2.mul(frobenius_coeff_fq12_c1) 416 | ) 417 | ); 418 | } 419 | 420 | else { 421 | let frobenius_coeff_fq12_c1 = new Fq2( 422 | new Fq(18566938241244942414004596690298913868373833782006617400804628704885040364344n), 423 | new Fq(16165975933942742336466353786298926857552937457188450663314217659523851788715n) 424 | ); 425 | 426 | return new Fq12( 427 | c0, 428 | new Fq6( 429 | c1.c0.mul(frobenius_coeff_fq12_c1), 430 | c1.c1.mul(frobenius_coeff_fq12_c1), 431 | c1.c2.mul(frobenius_coeff_fq12_c1) 432 | ) 433 | ); 434 | } 435 | 436 | } 437 | 438 | // we didn't test this yet. 439 | static one() { 440 | return new Fq12( 441 | new Fq6( 442 | new Fq2( 443 | new Fq(1n), 444 | new Fq(0n) 445 | ), 446 | new Fq2( 447 | new Fq(0n), 448 | new Fq(0n) 449 | ), 450 | new Fq2( 451 | new Fq(0n), 452 | new Fq(0n) 453 | ), 454 | ), 455 | new Fq6( 456 | new Fq2( 457 | new Fq(0n), 458 | new Fq(0n) 459 | ), 460 | new Fq2( 461 | new Fq(0n), 462 | new Fq(0n) 463 | ), 464 | new Fq2( 465 | new Fq(0n), 466 | new Fq(0n) 467 | ) 468 | ) 469 | ) 470 | } 471 | 472 | exp_by_x() { 473 | let res = Fq12.one(); 474 | 475 | for (let i = 0; i < 64; i++) { 476 | res = res.cyclotomic_square(); 477 | if (Pairing.BN_X_BINARY[i] == 1) { 478 | res = res.mul(this); 479 | } 480 | } 481 | 482 | return res; 483 | } 484 | 485 | } 486 | 487 | -------------------------------------------------------------------------------- /src/pairing_new.ts: -------------------------------------------------------------------------------- 1 | import G1 from './g1_new'; 2 | import G2 from './g2_new'; 3 | import Fq12 from './fq12'; 4 | import Fq6 from './fq6'; 5 | import Fq2 from './fq2'; 6 | import Fq from './fq'; 7 | import G1Affine from './g1_affine'; 8 | import G2Affine from './g2_affine'; 9 | import { convertToObject, resolveModuleName } from 'typescript'; 10 | 11 | class LineEval { 12 | r: G2 13 | result: G2 14 | 15 | constructor(r: G2, result: G2) { 16 | this.r = r; 17 | this.result = result; 18 | } 19 | } 20 | 21 | export default class Pairing{ 22 | 23 | static BN_X_BINARY = [ 24 | 0, 1, 0, 0, 0, 1, 0, 0, 25 | 1, 1, 1, 0, 1, 0, 0, 1, 26 | 1, 0, 0, 1, 0, 0, 1, 0, 27 | 1, 0, 1, 1, 0, 1, 0, 0, 28 | 0, 1, 0, 0, 1, 0, 1, 0, 29 | 0, 1, 1, 0, 1, 0, 0, 1, 30 | 0, 0, 0, 0, 1, 0, 0, 1, 31 | 1, 1, 1, 1, 0, 0, 0, 1 32 | ]; 33 | 34 | static SIX_U_PLUS_2_NAF = [ 35 | 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 36 | 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 37 | 0, 1, 0, 1, 1, 38 | ]; 39 | 40 | static XI_TO_Q_MINUS_1_OVER_2 = new Fq2( 41 | new Fq(2821565182194536844548159561693502659359617185244120367078079554186484126554n), 42 | new Fq(3505843767911556378687030309984248845540243509899259641013678093033130930403n) 43 | ); 44 | 45 | static final_exponentiation(r: Fq12) { 46 | let f1 = r; 47 | f1 = f1.conjugate(); 48 | 49 | let f2 = r.invert(); 50 | r = f1; 51 | r = r.mul(f2); 52 | f2 = r; 53 | r = r.frobenius_map(2n); 54 | r = r.mul(f2); 55 | // Buraya kadar doğru. 56 | 57 | let fp = r; 58 | fp = fp.frobenius_map(1n); 59 | 60 | let fp2 = r; 61 | fp2 = fp2.frobenius_map(2n); 62 | let fp3 = fp2; 63 | fp3 = fp3.frobenius_map(1n); 64 | 65 | // Buraya kadar doğru 66 | 67 | let fu = r; 68 | fu = fu.exp_by_x(); 69 | 70 | let fu2 = fu; 71 | fu2 = fu2.exp_by_x(); 72 | 73 | let fu3 = fu2; 74 | fu3 = fu3.exp_by_x(); 75 | 76 | // Buraya kadar doğru 77 | 78 | let y3 = fu; 79 | y3 = y3.frobenius_map(1n); 80 | 81 | let fu2p = fu2; 82 | fu2p = fu2p.frobenius_map(1n); 83 | 84 | let fu3p = fu3; 85 | fu3p = fu3p.frobenius_map(1n); 86 | 87 | let y2 = fu2; 88 | y2 = y2.frobenius_map(2n); 89 | 90 | // Buraya kadar doğru 91 | 92 | let y0 = fp; 93 | y0 = y0.mul(fp2); 94 | y0 = y0.mul(fp3); 95 | 96 | let y1 = r; 97 | y1 = y1.conjugate(); 98 | 99 | let y5 = fu2; 100 | y5 = y5.conjugate(); 101 | 102 | y3 = y3.conjugate(); 103 | 104 | let y4 = fu; 105 | y4 = y4.mul(fu2p); 106 | y4 = y4.conjugate(); 107 | 108 | let y6 = fu3; 109 | y6 = y6.mul(fu3p); 110 | y6 = y6.conjugate(); 111 | 112 | // Buraya kadar doğru 113 | 114 | y6 = y6.cyclotomic_square(); 115 | 116 | // Buraya kadar doğru 117 | 118 | y6 = y6.mul(y4); 119 | y6 = y6.mul(y5); 120 | 121 | let t1 = y3; 122 | t1 = t1.mul(y5); 123 | t1 = t1.mul(y6); 124 | 125 | y6 = y6.mul(y2); 126 | 127 | t1 = t1.cyclotomic_square(); 128 | t1 = t1.mul(y6); 129 | t1 = t1.cyclotomic_square(); 130 | 131 | let t0 = t1; 132 | t0 = t0.mul(y1); 133 | 134 | t1 = t1.mul(y0); 135 | 136 | t0 = t0.cyclotomic_square(); 137 | t0 = t0.mul(t1); 138 | 139 | return t0; 140 | } 141 | 142 | static doubling_step_with_p(r: G2, p:G1Affine) { 143 | let tmp0 = r.x; 144 | tmp0 = tmp0.square(); 145 | 146 | let tmp1 = r.y; 147 | tmp1 = tmp1.square(); 148 | 149 | let tmp2 = tmp1; 150 | tmp2 = tmp2.square(); 151 | 152 | let tmp3 = tmp1; 153 | tmp3 = tmp3.add(r.x); 154 | tmp3 = tmp3.square(); 155 | tmp3 = tmp3.sub(tmp0); 156 | tmp3 = tmp3.sub(tmp2); 157 | tmp3 = tmp3.double(); 158 | 159 | let tmp4 = tmp0; 160 | tmp4 = tmp4.double(); 161 | tmp4 = tmp4.add(tmp0); 162 | 163 | let tmp6 = r.x; 164 | tmp6 = tmp6.add(tmp4); 165 | 166 | let tmp5 = tmp4; 167 | tmp5 = tmp5.square(); 168 | 169 | let zsquared = r.z; 170 | zsquared = zsquared.square(); 171 | 172 | let cx = tmp5; 173 | cx = cx.sub(tmp3); 174 | cx = cx.sub(tmp3); 175 | 176 | let cz = r.z.add(r.y); 177 | cz = cz.square(); 178 | cz = cz.sub(tmp1); 179 | cz = cz.sub(zsquared); 180 | 181 | let cy = tmp3; 182 | cy = cy.sub(cx); 183 | cy = cy.mul(tmp4); 184 | 185 | tmp2 = tmp2.double(); 186 | tmp2 = tmp2.double(); 187 | tmp2 = tmp2.double(); 188 | 189 | cy = cy.sub(tmp2); 190 | 191 | // It is correct up to here. 192 | 193 | tmp3 = tmp4; 194 | tmp3 = tmp3.mul(zsquared); 195 | tmp3 = tmp3.double(); 196 | tmp3 = tmp3.neg(); 197 | tmp3.c0 = tmp3.c0.mul(p.x); // algorithm 7 198 | tmp3.c1 = tmp3.c1.mul(p.x); 199 | 200 | tmp6 = tmp6.square(); 201 | tmp6 = tmp6.sub(tmp0); 202 | tmp6 = tmp6.sub(tmp5); 203 | 204 | tmp1 = tmp1.double(); 205 | tmp1 = tmp1.double(); 206 | 207 | tmp6 = tmp6.sub(tmp1); 208 | 209 | tmp0 = cz; 210 | tmp0 = tmp0.mul(zsquared); 211 | tmp0 = tmp0.double(); 212 | tmp0.c0 = tmp0.c0.mul(p.y); 213 | tmp1.c1 = tmp1.c1.mul(p.y); 214 | 215 | 216 | return new LineEval( 217 | new G2( 218 | cx, 219 | cy, 220 | cz 221 | ), 222 | new G2( 223 | tmp0, 224 | tmp3, 225 | tmp6 226 | ) 227 | ); 228 | } 229 | 230 | // Tested. 231 | static doubling_step(r: G2) { 232 | let tmp0 = r.x; 233 | tmp0 = tmp0.square(); 234 | 235 | let tmp1 = r.y; 236 | tmp1 = tmp1.square(); 237 | 238 | let tmp2 = tmp1; 239 | tmp2 = tmp2.square(); 240 | 241 | let tmp3 = tmp1; 242 | tmp3 = tmp3.add(r.x); 243 | tmp3 = tmp3.square(); 244 | tmp3 = tmp3.sub(tmp0); 245 | tmp3 = tmp3.sub(tmp2); 246 | tmp3 = tmp3.double(); 247 | 248 | let tmp4 = tmp0; 249 | tmp4 = tmp4.double(); 250 | tmp4 = tmp4.add(tmp0); 251 | 252 | let tmp6 = r.x; 253 | tmp6 = tmp6.add(tmp4); 254 | 255 | let tmp5 = tmp4; 256 | tmp5 = tmp5.square(); 257 | 258 | let zsquared = r.z; 259 | zsquared = zsquared.square(); // zsquared is correct. 260 | 261 | let cx = tmp5; 262 | cx = cx.sub(tmp3); 263 | cx = cx.sub(tmp3); 264 | 265 | //let cz = r.y; // This is wrong. 266 | 267 | 268 | let cz = r.z.add(r.y); 269 | cz = cz.square(); 270 | cz = cz.sub(tmp1); 271 | cz = cz.sub(zsquared); 272 | 273 | let cy = tmp3; 274 | cy = cy.sub(cx); 275 | cy = cy.mul(tmp4); 276 | 277 | tmp2 = tmp2.double(); 278 | tmp2 = tmp2.double(); 279 | tmp2 = tmp2.double(); 280 | 281 | cy = cy.sub(tmp2); 282 | 283 | // It is correct up to here. 284 | 285 | tmp3 = tmp4; 286 | tmp3 = tmp3.mul(zsquared); 287 | tmp3 = tmp3.double(); 288 | tmp3 = tmp3.neg(); 289 | 290 | tmp6 = tmp6.square(); 291 | tmp6 = tmp6.sub(tmp0); 292 | tmp6 = tmp6.sub(tmp5); 293 | 294 | tmp1 = tmp1.double(); 295 | tmp1 = tmp1.double(); 296 | 297 | tmp6 = tmp6.sub(tmp1); 298 | 299 | tmp0 = cz; 300 | tmp0 = tmp0.mul(zsquared); 301 | tmp0 = tmp0.double(); 302 | 303 | 304 | return new LineEval( 305 | new G2( 306 | cx, 307 | cy, 308 | cz 309 | ), 310 | new G2( 311 | tmp0, 312 | tmp3, 313 | tmp6 314 | ) 315 | ); 316 | 317 | } 318 | 319 | static addition_step_with_p(r: G2, q_affine: G2Affine, p: G1Affine) { 320 | let zsquared = r.z; 321 | zsquared = zsquared.square(); 322 | 323 | let t0 = zsquared; 324 | t0 = t0.mul(q_affine.x); 325 | 326 | let ysquared = q_affine.y; 327 | ysquared = ysquared.square(); 328 | 329 | let t1 = q_affine.y; 330 | t1 = t1.add(r.z); 331 | t1 = t1.square(); 332 | t1 = t1.sub(ysquared); 333 | t1 = t1.sub(zsquared); 334 | t1 = t1.mul(zsquared); 335 | 336 | let t2 = t0; 337 | t2 = t2.sub(r.x); 338 | 339 | let t3 = t2; 340 | t3 = t3.square(); 341 | 342 | let t4 = t3; 343 | t4 = t4.double(); 344 | t4 = t4.double(); 345 | 346 | let t5 = t4; 347 | t5 = t5.mul(t2); 348 | 349 | let t6 = t1; 350 | t6 = t6.sub(r.y); 351 | t6 = t6.sub(r.y); 352 | 353 | let t9 = t6; 354 | t9 = t9.mul(q_affine.x); 355 | 356 | // stay at line 348. 357 | let t7 = t4; 358 | t7 = t7.mul(r.x); 359 | 360 | let cx = t6; 361 | cx = cx.square(); 362 | cx = cx.sub(t5); 363 | cx = cx.sub(t7); 364 | cx = cx.sub(t7); 365 | 366 | let cz = r.z.add(t2); 367 | cz = cz.square(); 368 | cz = cz.sub(zsquared); 369 | cz = cz.sub(t3); 370 | 371 | let t10 = q_affine.y; 372 | t10 = t10.add(cz); 373 | 374 | let t8 = t7; 375 | t8 = t8.sub(cx); 376 | t8 = t8.mul(t6); 377 | 378 | t0 = r.y; 379 | t0 = t0.mul(t5); 380 | t0 = t0.double(); 381 | 382 | let cy = t8; 383 | cy = cy.sub(t0); 384 | 385 | t10 = t10.square(); 386 | t10 = t10.sub(ysquared); 387 | 388 | let ztsquared = cz; 389 | ztsquared = ztsquared.square(); 390 | 391 | t10 = t10.sub(ztsquared); 392 | 393 | t9 = t9.double(); 394 | t9 = t9.sub(t10); 395 | 396 | t10 = cz; 397 | t10 = t10.double(); // (algorithm 7???) yp ile çarpmadık??? 398 | t10.c0 = t10.c0.mul(p.y); 399 | t10.c1 = t10.c1.mul(p.y); 400 | 401 | t6 = t6.neg(); 402 | 403 | t1 = t6; 404 | t1 = t1.double(); // (algorithm 7???) xp ile çarpmadık??? 405 | t1.c0 = t1.c0.mul(p.x); 406 | t1.c1 = t1.c1.mul(p.y); 407 | 408 | 409 | return new LineEval( 410 | new G2( 411 | cx, 412 | cy, 413 | cz 414 | ), 415 | new G2( 416 | t10, 417 | t1, 418 | t9 419 | ) 420 | ); 421 | } 422 | 423 | // Burada, q_affine G2 Affine olacak. Ben bunu direk G2 olarak aldım. 424 | // Tested. 425 | static addition_step(r: G2, q_affine: G2Affine) { 426 | let zsquared = r.z; 427 | zsquared = zsquared.square(); 428 | 429 | let t0 = zsquared; 430 | t0 = t0.mul(q_affine.x); 431 | 432 | let ysquared = q_affine.y; 433 | ysquared = ysquared.square(); 434 | 435 | let t1 = q_affine.y; 436 | t1 = t1.add(r.z); 437 | t1 = t1.square(); 438 | t1 = t1.sub(ysquared); 439 | t1 = t1.sub(zsquared); 440 | t1 = t1.mul(zsquared); 441 | 442 | let t2 = t0; 443 | t2 = t2.sub(r.x); 444 | 445 | let t3 = t2; 446 | t3 = t3.square(); 447 | 448 | let t4 = t3; 449 | t4 = t4.double(); 450 | t4 = t4.double(); 451 | 452 | let t5 = t4; 453 | t5 = t5.mul(t2); 454 | 455 | let t6 = t1; 456 | t6 = t6.sub(r.y); 457 | t6 = t6.sub(r.y); 458 | 459 | let t9 = t6; 460 | t9 = t9.mul(q_affine.x); 461 | 462 | // stay at line 348. 463 | let t7 = t4; 464 | t7 = t7.mul(r.x); 465 | 466 | let cx = t6; 467 | cx = cx.square(); 468 | cx = cx.sub(t5); 469 | cx = cx.sub(t7); 470 | cx = cx.sub(t7); 471 | 472 | let cz = r.z.add(t2); 473 | cz = cz.square(); 474 | cz = cz.sub(zsquared); 475 | cz = cz.sub(t3); 476 | 477 | let t10 = q_affine.y; 478 | t10 = t10.add(cz); 479 | 480 | let t8 = t7; 481 | t8 = t8.sub(cx); 482 | t8 = t8.mul(t6); 483 | 484 | t0 = r.y; 485 | t0 = t0.mul(t5); 486 | t0 = t0.double(); 487 | 488 | let cy = t8; 489 | cy = cy.sub(t0); 490 | 491 | t10 = t10.square(); 492 | t10 = t10.sub(ysquared); 493 | 494 | let ztsquared = cz; 495 | ztsquared = ztsquared.square(); 496 | 497 | t10 = t10.sub(ztsquared); 498 | 499 | t9 = t9.double(); 500 | t9 = t9.sub(t10); 501 | 502 | t10 = cz; 503 | t10 = t10.double(); // (algorithm 7???) yp ile çarpmadık??? 504 | 505 | t6 = t6.neg(); 506 | 507 | t1 = t6; 508 | t1 = t1.double(); // (algorithm 7???) xp ile çarpmadık??? 509 | 510 | 511 | return new LineEval( 512 | new G2( 513 | cx, 514 | cy, 515 | cz 516 | ), 517 | new G2( 518 | t10, 519 | t1, 520 | t9 521 | ) 522 | ); 523 | 524 | 525 | } 526 | 527 | static ell(f: Fq12, coeff: G2, p_affine: G1Affine) { 528 | let c0 = coeff.x; 529 | let c1 = coeff.y; 530 | 531 | c0.c0 = c0.c0.mul(p_affine.y); 532 | c0.c1 = c0.c1.mul(p_affine.y); 533 | 534 | 535 | c1.c0 = c1.c0.mul(p_affine.x); 536 | c1.c1 = c1.c1.mul(p_affine.x); 537 | 538 | // coeff_0 539 | let res_f = f.mul_by_034(c0, c1, coeff.z); // 540 | return res_f; 541 | } 542 | 543 | static miller_loop(Q: G2Affine, P: G1Affine) { 544 | let f = Fq12.one(); 545 | let r = Q.to_proj(); 546 | 547 | let negq = new G2Affine( 548 | Q.x, 549 | Q.y.neg() 550 | ); 551 | 552 | for (let i = 64; i > 0; i--) { 553 | if (i != 64) { 554 | f = f.square(); 555 | } 556 | 557 | let line_eval = Pairing.doubling_step(r); 558 | r = line_eval.r; 559 | let result = line_eval.result; 560 | // Buraya kadar doğru 561 | 562 | 563 | f = Pairing.ell(f, result, P); 564 | /*result.x.c0 = result.x.c0.mul(P.y); 565 | result.x.c1 = result.x.c1.mul(P.y); 566 | 567 | result.y.c0 = result.x.c0.mul(P.x); 568 | result.y.c1 = result.x.c1.mul(P.x);*/ 569 | 570 | let x = Pairing.SIX_U_PLUS_2_NAF[i - 1]; 571 | 572 | if (x == 1) { 573 | 574 | let line_eval = Pairing.addition_step(r, Q); 575 | r = line_eval.r; 576 | let result = line_eval.result; 577 | 578 | f = Pairing.ell(f, result, P); 579 | /*result.x.c0 = result.x.c0.mul(P.y); 580 | result.x.c1 = result.x.c1.mul(P.y); 581 | 582 | result.y.c0 = result.x.c0.mul(P.x); 583 | result.y.c1 = result.x.c1.mul(P.x);*/ 584 | 585 | } 586 | 587 | if (x == -1) { 588 | let line_eval = Pairing.addition_step(r, negq); 589 | r = line_eval.r; 590 | let result = line_eval.result; 591 | f = Pairing.ell(f, result, P); 592 | /*result.x.c0 = result.x.c0.mul(P.y); 593 | result.x.c1 = result.x.c1.mul(P.y); 594 | 595 | result.y.c0 = result.x.c0.mul(P.x); 596 | result.y.c1 = result.x.c1.mul(P.x);*/ 597 | } 598 | } 599 | 600 | // f after loop is correct. 601 | // add those functions 602 | console.log("Q after loop is:") 603 | console.log(Q.x.c0.toBigInt()); 604 | console.log(Q.x.c1.toBigInt()); 605 | console.log(Q.y.c0.toBigInt()); 606 | console.log(Q.y.c1.toBigInt()); 607 | 608 | let x_c0 = Q.x.c0; 609 | let x_c1 = Q.x.c1; 610 | let y_c0 = Q.y.c0; 611 | let y_c1 = Q.y.c1; 612 | 613 | let q1 = new G2Affine( 614 | new Fq2( 615 | x_c0, 616 | x_c1 617 | ), 618 | new Fq2( 619 | y_c0, 620 | y_c1 621 | ) 622 | ); 623 | 624 | q1.x.c1 = q1.x.c1.neg(); 625 | 626 | q1.x = q1.x.mul(new Fq2( 627 | new Fq(21575463638280843010398324269430826099269044274347216827212613867836435027261n), 628 | new Fq(10307601595873709700152284273816112264069230130616436755625194854815875713954n) 629 | )); 630 | 631 | q1.y.c1 = q1.y.c1.neg(); 632 | q1.y = q1.y.mul(this.XI_TO_Q_MINUS_1_OVER_2); 633 | 634 | console.log("Q1 is:") 635 | console.log(q1.x.c0.toBigInt()); 636 | console.log(q1.x.c1.toBigInt()); 637 | console.log(q1.y.c0.toBigInt()); 638 | console.log(q1.y.c1.toBigInt()); 639 | 640 | // does it work correctly? 641 | let line_eval = Pairing.addition_step(r, q1); 642 | r = line_eval.r; 643 | let result = line_eval.result; 644 | 645 | f = Pairing.ell(f, result, P); 646 | result.x.c0 = result.x.c0.mul(P.y); 647 | result.x.c1 = result.x.c1.mul(P.y); 648 | 649 | result.y.c0 = result.x.c0.mul(P.x); 650 | result.y.c1 = result.x.c1.mul(P.x); 651 | 652 | let minusq2 = Q; 653 | minusq2.x = minusq2.x.mul( 654 | new Fq2( 655 | new Fq(21888242871839275220042445260109153167277707414472061641714758635765020556616n), 656 | new Fq(0n) 657 | ) 658 | ); 659 | 660 | console.log("minusq2 is:") 661 | console.log(minusq2.x.c0.toBigInt()); 662 | console.log(minusq2.x.c1.toBigInt()); 663 | console.log(minusq2.y.c0.toBigInt()); 664 | console.log(minusq2.y.c1.toBigInt()); 665 | 666 | line_eval = Pairing.addition_step(r, minusq2); 667 | r = line_eval.r; 668 | result = line_eval.result; 669 | 670 | f = Pairing.ell(f, result, P); 671 | console.log("r after loop is:") 672 | console.log(r.x.c0.toBigInt()); 673 | console.log(r.x.c1.toBigInt()); 674 | console.log(r.y.c0.toBigInt()); 675 | console.log(r.y.c1.toBigInt()); 676 | console.log(r.z.c0.toBigInt()); 677 | console.log(r.z.c1.toBigInt()); 678 | 679 | 680 | console.log("Q after loop is:") 681 | console.log(Q.x.c0.toBigInt()); 682 | console.log(Q.x.c1.toBigInt()); 683 | console.log(Q.y.c0.toBigInt()); 684 | console.log(Q.y.c1.toBigInt()); 685 | 686 | 687 | return f; 688 | 689 | } 690 | 691 | static miller_loop_with_p(Q: G2Affine, P: G1Affine) { 692 | let f = Fq12.one(); 693 | let r = Q.to_proj(); 694 | 695 | let negq = new G2Affine( 696 | Q.x, 697 | Q.y.neg() 698 | ); 699 | 700 | 701 | for (let i = 64; i >= 0; i--) { 702 | /*if (i != 64) { 703 | f = f.square(); 704 | }*/ 705 | 706 | f = f.square(); 707 | 708 | let line_eval = this.doubling_step_with_p(r, P); 709 | r = line_eval.r; 710 | let result = line_eval.result; 711 | f = f.mul_by_034(result.x, result.y, result.z); 712 | 713 | let x = Pairing.SIX_U_PLUS_2_NAF[i - 1]; 714 | 715 | if (x == 1) { 716 | let line_eval = this.addition_step_with_p(r, Q, P); 717 | r = line_eval.r; 718 | let result = line_eval.result; 719 | f = f.mul_by_034(result.x, result.y, result.z); 720 | 721 | if (i == 64) { 722 | console.log("result after addition is:") 723 | console.log(result.x.c0.toBigInt()); 724 | console.log(result.x.c1.toBigInt()); 725 | console.log(result.y.c0.toBigInt()); 726 | console.log(result.y.c1.toBigInt()); 727 | console.log(result.z.c0.toBigInt()); 728 | console.log(result.z.c1.toBigInt()); 729 | } 730 | } 731 | 732 | if (x == -1) { 733 | let line_eval = this.addition_step_with_p(r, negq, P); 734 | r = line_eval.r; 735 | let result = line_eval.result; 736 | f = f.mul_by_034(result.x, result.y, result.z); 737 | } 738 | } 739 | 740 | return f; 741 | 742 | } 743 | 744 | static pair(Q: G2Affine, P: G1Affine) { 745 | let f = Pairing.miller_loop(Q, P); 746 | f = Pairing.final_exponentiation(f); 747 | return f; 748 | } 749 | 750 | static pair_with_p(Q: G2Affine, P: G1Affine) { 751 | let f = Pairing.miller_loop_with_p(Q, P); 752 | f = Pairing.final_exponentiation(f); 753 | return f; 754 | } 755 | } -------------------------------------------------------------------------------- /src/pairing_new.test.ts: -------------------------------------------------------------------------------- 1 | import Pairing from "./pairing_new"; 2 | import Fq12 from "./fq12"; 3 | import Fq6 from "./fq6"; 4 | import Fq2 from "./fq2"; 5 | import Fq from "./fq"; 6 | import G1 from "./g1_new"; 7 | import G2 from "./g2_new"; 8 | import { convertToObject, isConstructorDeclaration } from "typescript"; 9 | import G2Affine from "./g2_affine"; 10 | import G1Affine from "./g1_affine"; 11 | 12 | 13 | describe('test pairing functions', function() { 14 | 15 | //Fq12 result after final_exponentiation 16 | 17 | //c0: c0: c0: 18 | //798502083397251921633833674883831104730682408543675020367286750497807698645 19 | //c0: c0: c1: 20 | //20793674778978652694944268622468059656139754448735949818355501586028955257569 21 | //c0: c1: c0: 22 | //19048478524633283498085811054381399442903474179854423089240633507472524150262 23 | //c0: c1: c1: 24 | //15038731096124620452385470562243005872807692220833222100737078380290179293601 25 | //c0: c2: c0: 26 | //19681044767574525412286316344330609819205364432495350388091397098350158009791 27 | //c0: c2: c1: 28 | //14169609043629130412242917837138631876517067323018367346926035791950997191660 29 | //c1: c0: c0: 30 | //21681460614944590471230154167872844780267038250831055610345302175827879148819 31 | //c1: c0: c1: 32 | //8747515195756416269723830997182137311552961765373288911025484618924826387952 33 | //c1: c1: c0: 34 | //14855910687706175046573301839761345733585599107938739358093378151700479377612 35 | //c1: c1: c1: 36 | //8903458072238520772063941873669153241276993002477451201620137453911786119461 37 | //c1: c2: c0: 38 | //12657732548725281370731292049617675660830024822575316295880259464449340428763 39 | //c1: c2: c1: 40 | //6884837954578062278521836969300104051613900678416646060390403430109502310478 41 | 42 | it('Test final exponentiation', function() { 43 | console.log("test final exponentiation "); 44 | 45 | let second = new Fq12( 46 | new Fq6( 47 | new Fq2( 48 | new Fq(21227010742668523973779795892080484478413631586992185774992397774453111499562n), 49 | new Fq(19226519837628619696197361438039192285186559783794253066594478201300567625581n) 50 | ), 51 | new Fq2( 52 | new Fq(7782287104470559324105132304997884557026788032401170325684944465605236395051n), 53 | new Fq(19110893883636139580674900407653400921517208489522902969760806789675732237443n) 54 | ), 55 | new Fq2( 56 | new Fq(13373558987747729767106266411641782708520066622224553970810646960119770906482n), 57 | new Fq(8239735462772116299759198943303716067067211972951745657386023141164294230159n), 58 | ) 59 | ), 60 | 61 | new Fq6( 62 | new Fq2( 63 | new Fq(19723498938913580838527010796995565664940964702558430218792533379614170175584n), 64 | new Fq(19198937630784884904531985231983944570953927007639024736778645015422755148596n) 65 | ), 66 | new Fq2( 67 | new Fq(318460156404207635097638769497134177093016410663420631112968904066667788855n), 68 | new Fq(5811915892240812086868837101820778755877273314773348243459728092795714036353n) 69 | ), 70 | new Fq2( 71 | new Fq(20555792769679092785671034318258460903890555657119752069678898280830359015944n), 72 | new Fq(3839526312266986973044379943534614883360461121168709130959429802008624145960n), 73 | ) 74 | ) 75 | ); 76 | 77 | let res = Pairing.final_exponentiation(second); 78 | 79 | console.log("The final exponentiation result is:"); 80 | console.log(res.c0.c0.c0.toBigInt()); 81 | console.log(res.c0.c0.c1.toBigInt()); 82 | console.log(res.c0.c1.c0.toBigInt()); 83 | console.log(res.c0.c1.c1.toBigInt()); 84 | console.log(res.c0.c2.c0.toBigInt()); 85 | console.log(res.c0.c2.c1.toBigInt()); 86 | console.log(res.c1.c0.c0.toBigInt()); 87 | console.log(res.c1.c0.c1.toBigInt()); 88 | console.log(res.c1.c1.c0.toBigInt()); 89 | console.log(res.c1.c1.c1.toBigInt()); 90 | console.log(res.c1.c2.c0.toBigInt()); 91 | console.log(res.c1.c2.c1.toBigInt()); 92 | 93 | }); 94 | 95 | it('Test final exponentiation', function() { 96 | console.log("test final exponentiation "); 97 | 98 | let second = new Fq12( 99 | new Fq6( 100 | new Fq2( 101 | new Fq(21227010742668523973779795892080484478413631586992185774992397774453111499562n), 102 | new Fq(19226519837628619696197361438039192285186559783794253066594478201300567625581n) 103 | ), 104 | new Fq2( 105 | new Fq(7782287104470559324105132304997884557026788032401170325684944465605236395051n), 106 | new Fq(19110893883636139580674900407653400921517208489522902969760806789675732237443n) 107 | ), 108 | new Fq2( 109 | new Fq(13373558987747729767106266411641782708520066622224553970810646960119770906482n), 110 | new Fq(8239735462772116299759198943303716067067211972951745657386023141164294230159n), 111 | ) 112 | ), 113 | 114 | new Fq6( 115 | new Fq2( 116 | new Fq(19723498938913580838527010796995565664940964702558430218792533379614170175584n), 117 | new Fq(19198937630784884904531985231983944570953927007639024736778645015422755148596n) 118 | ), 119 | new Fq2( 120 | new Fq(318460156404207635097638769497134177093016410663420631112968904066667788855n), 121 | new Fq(5811915892240812086868837101820778755877273314773348243459728092795714036353n) 122 | ), 123 | new Fq2( 124 | new Fq(20555792769679092785671034318258460903890555657119752069678898280830359015944n), 125 | new Fq(3839526312266986973044379943534614883360461121168709130959429802008624145960n), 126 | ) 127 | ) 128 | ); 129 | 130 | let g1_generator = G1.generator(); 131 | let g1_generator_affine = g1_generator.to_affine(); 132 | 133 | let g2_generator = G2.generator(); 134 | let g2_generator_affine = g2_generator.to_affine(); 135 | 136 | //let miller_result = Pairing.miller_loop(g2_generator_affine); 137 | let res = Pairing.final_exponentiation(second); 138 | 139 | console.log("The final exponentiation result is:"); 140 | console.log(res.c0.c0.c0.toBigInt()); 141 | console.log(res.c0.c0.c1.toBigInt()); 142 | console.log(res.c0.c1.c0.toBigInt()); 143 | console.log(res.c0.c1.c1.toBigInt()); 144 | console.log(res.c0.c2.c0.toBigInt()); 145 | console.log(res.c0.c2.c1.toBigInt()); 146 | console.log(res.c1.c0.c0.toBigInt()); 147 | console.log(res.c1.c0.c1.toBigInt()); 148 | console.log(res.c1.c1.c0.toBigInt()); 149 | console.log(res.c1.c1.c1.toBigInt()); 150 | console.log(res.c1.c2.c0.toBigInt()); 151 | console.log(res.c1.c2.c1.toBigInt()); 152 | 153 | }); 154 | 155 | /*g2_affine_3g 156 | G2 x c0 157 | 2725019753478801796453339367788033689375851816420509565303521482350756874229 158 | G2 x c1 159 | 7273165102799931111715871471550377909735733521218303035754523677688038059653 160 | G2 y c0 161 | 2512659008974376214222774206987427162027254181373325676825515531566330959255 162 | G2 y c1 163 | 957874124722006818841961785324909313781880061366718538693995380805373202866 164 | G2 z c0 165 | 0 166 | G2 z c1 167 | 0 168 | g2_2g 169 | G2 x c0 170 | 18064657650266314310872833882734510304469342224960895762840452673540398385663 171 | G2 x c1 172 | 15767209469806156760211170373387620603270210844572625444480773861832148323813 173 | G2 y c0 174 | 18350387758438165722514006433324734852126505429007818091896560652419680779208 175 | G2 y c1 176 | 2361120538552305763462588552289584032113666280040005078430227626567900900889 177 | G2 z c0 178 | 11295011439305748432050915375304030887315222387144299555868531462511479541127 179 | G2 z c1 180 | 21586188435259680269345972498488110271568572496353012928929868286300284796401 181 | addition result 182 | G2 x c0 183 | 14544768148792632680073221983566693239583282104557296657848306123566393475730 184 | G2 x c1 185 | 15034324394469490987779704591448025941722072015306291430099460905795412688577 186 | G2 y c0 187 | 11002011155701785813972642690498120535862192909530050003961781729574140785553 188 | G2 y c1 189 | 10463967624402083525436831344787392148296280284977976166619878361459662805605 190 | G2 z c0 191 | 8863921422321631853541600922641661429758378788881107427311426765831451334272 192 | G2 z c1 193 | 5034616795582565734225936021994665960773476499030844842075241925330862037999*/ 194 | 195 | it('Test addition step', function() { 196 | console.log("Test g1 affine and projective transform"); 197 | let g2_affine_3g = new G2Affine( 198 | new Fq2( 199 | new Fq(2725019753478801796453339367788033689375851816420509565303521482350756874229n), 200 | new Fq(7273165102799931111715871471550377909735733521218303035754523677688038059653n) 201 | ), 202 | new Fq2( 203 | new Fq(2512659008974376214222774206987427162027254181373325676825515531566330959255n), 204 | new Fq(957874124722006818841961785324909313781880061366718538693995380805373202866n) 205 | ) 206 | ) 207 | 208 | let g2_2g = new G2( 209 | new Fq2( 210 | new Fq(18064657650266314310872833882734510304469342224960895762840452673540398385663n), 211 | new Fq(15767209469806156760211170373387620603270210844572625444480773861832148323813n) 212 | ), 213 | new Fq2( 214 | new Fq(18350387758438165722514006433324734852126505429007818091896560652419680779208n), 215 | new Fq(2361120538552305763462588552289584032113666280040005078430227626567900900889n) 216 | ), 217 | new Fq2( 218 | new Fq(11295011439305748432050915375304030887315222387144299555868531462511479541127n), 219 | new Fq(21586188435259680269345972498488110271568572496353012928929868286300284796401n) 220 | ) 221 | ) 222 | 223 | let g2_generator = G2.generator(); 224 | let g2_generator_2g = g2_generator.add(g2_generator); 225 | let g2_generator_3g = g2_generator_2g.add(g2_generator); 226 | 227 | let g2_generator_3g_affine = g2_generator_3g.to_affine(); 228 | 229 | console.log(g2_generator_2g.x.c0.toBigInt()); 230 | console.log(g2_generator_2g.x.c1.toBigInt()); 231 | console.log(g2_generator_2g.y.c0.toBigInt()); 232 | console.log(g2_generator_2g.y.c1.toBigInt()); 233 | console.log(g2_generator_2g.z.c0.toBigInt()); 234 | console.log(g2_generator_2g.z.c1.toBigInt()); 235 | 236 | console.log(g2_generator_3g_affine.x.c0.toBigInt()); 237 | console.log(g2_generator_3g_affine.x.c1.toBigInt()); 238 | console.log(g2_generator_3g_affine.y.c0.toBigInt()); 239 | console.log(g2_generator_3g_affine.y.c1.toBigInt()); 240 | 241 | let addition_result = Pairing.addition_step(g2_2g, g2_affine_3g); 242 | 243 | /*console.log(addition_result.x.c0.toBigInt()); 244 | console.log(addition_result.x.c1.toBigInt()); 245 | console.log(addition_result.y.c0.toBigInt()); 246 | console.log(addition_result.y.c1.toBigInt()); 247 | console.log(addition_result.z.c0.toBigInt()); 248 | console.log(addition_result.z.c1.toBigInt());*/ 249 | 250 | }); 251 | 252 | /*doubling result doubling_step(2 * G) 253 | G2 x c0 254 | 15907470672758763390522514767003803497931353299914271700526213920442476042295 255 | G2 x c1 256 | 20783224935215815488584337979997070790192642887381753011555001201094594645160 257 | G2 y c0 258 | 534563814371495978974146195478125326052207300123260898857011675883367199460 259 | G2 y c1 260 | 7451553101180931993360714965623705913038106028499313570088137992249185208430 261 | G2 z c0 262 | 587737556357335807751429292753855402511169724545807108531042764320320964969 263 | G2 z c1 264 | 7851120854422305789899027307305441383200543189437963269032829892620510819590*/ 265 | 266 | it('Test doubling step', function() { 267 | console.log("doubling_step(2 * G) comparison test"); 268 | 269 | let g2_generator = G2.generator(); 270 | 271 | console.log(g2_generator.x.c0.toBigInt()); 272 | console.log(g2_generator.x.c1.toBigInt()); 273 | console.log(g2_generator.y.c0.toBigInt()); 274 | console.log(g2_generator.y.c1.toBigInt()); 275 | console.log(g2_generator.z.c0.toBigInt()); 276 | console.log(g2_generator.z.c1.toBigInt()); 277 | 278 | let g2_generator_double = g2_generator.double(); 279 | let g2_doubling_step_result = Pairing.doubling_step(g2_generator_double); 280 | 281 | /*console.log(g2_doubling_step_result.result.x.c0.toBigInt()); 282 | console.log(g2_doubling_step_result.x.c1.toBigInt()); 283 | console.log(g2_doubling_step_result.y.c0.toBigInt()); 284 | console.log(g2_doubling_step_result.y.c1.toBigInt()); 285 | console.log(g2_doubling_step_result.z.c0.toBigInt()); 286 | console.log(g2_doubling_step_result.z.c1.toBigInt());*/ 287 | 288 | }); 289 | 290 | it('Test doubling step 2', function() { 291 | console.log("Test G2"); 292 | 293 | let g2_generator = G2.generator(); 294 | let g2_generator_double = g2_generator.double(); 295 | 296 | console.log("g2_generator_double") 297 | console.log(g2_generator_double.x.c0.toBigInt()); 298 | console.log(g2_generator_double.x.c1.toBigInt()); 299 | console.log(g2_generator_double.y.c0.toBigInt()); 300 | console.log(g2_generator_double.y.c1.toBigInt()); 301 | console.log(g2_generator_double.z.c0.toBigInt()); 302 | console.log(g2_generator_double.z.c1.toBigInt()); 303 | 304 | let line_eval = Pairing.doubling_step(g2_generator_double); 305 | let g2_double_after_doubling = line_eval.r; 306 | 307 | console.log("g2_double after doubling") 308 | console.log(g2_double_after_doubling.x.c0.toBigInt()); 309 | console.log(g2_double_after_doubling.x.c1.toBigInt()); 310 | console.log(g2_double_after_doubling.y.c0.toBigInt()); 311 | console.log(g2_double_after_doubling.y.c1.toBigInt()); 312 | console.log(g2_double_after_doubling.z.c0.toBigInt()); 313 | console.log(g2_double_after_doubling.z.c1.toBigInt()); 314 | 315 | let g2_doubling_result = line_eval.result; 316 | 317 | console.log("Result after doubling") 318 | console.log(g2_doubling_result.x.c0.toBigInt()); 319 | console.log(g2_doubling_result.x.c1.toBigInt()); 320 | console.log(g2_doubling_result.y.c0.toBigInt()); 321 | console.log(g2_doubling_result.y.c1.toBigInt()); 322 | console.log(g2_doubling_result.z.c0.toBigInt()); 323 | console.log(g2_doubling_result.z.c1.toBigInt()); 324 | }); 325 | 326 | 327 | it('Test doubling step 3', function() { 328 | console.log("Test G2Affine"); 329 | 330 | let g2_generator = G2.generator(); 331 | 332 | let line_eval = Pairing.doubling_step(g2_generator); 333 | let g2_generator_after_doubling = line_eval.r; 334 | 335 | console.log("g2 generator after doubling"); 336 | console.log(g2_generator_after_doubling.x.c0.toBigInt()); 337 | console.log(g2_generator_after_doubling.x.c1.toBigInt()); 338 | console.log(g2_generator_after_doubling.y.c0.toBigInt()); 339 | console.log(g2_generator_after_doubling.y.c1.toBigInt()); 340 | console.log(g2_generator_after_doubling.z.c0.toBigInt()); 341 | console.log(g2_generator_after_doubling.z.c1.toBigInt()); 342 | 343 | 344 | let g2_generator_doubling_result = line_eval.result; 345 | 346 | console.log("g2 generator doubling result"); 347 | console.log(g2_generator_doubling_result.x.c0.toBigInt()); 348 | console.log(g2_generator_doubling_result.x.c1.toBigInt()); 349 | console.log(g2_generator_doubling_result.y.c0.toBigInt()); 350 | console.log(g2_generator_doubling_result.y.c1.toBigInt()); 351 | console.log(g2_generator_doubling_result.z.c0.toBigInt()); 352 | console.log(g2_generator_doubling_result.z.c1.toBigInt()); 353 | 354 | }); 355 | 356 | /*f_test after ecc is 357 | c0: c0: c0: 358 | 21539945124252953321531877303674042836786714281016248685273042078497397202541 359 | c0: c0: c1: 360 | 2462442388266997987471204595054592958310629132689122798291536816519114805370 361 | c0: c1: c0: 362 | 0 363 | c0: c1: c1: 364 | 0 365 | c0: c2: c0: 366 | 0 367 | c0: c2: c1: 368 | 0 369 | c1: c0: c0: 370 | 16991307846246862835209946494978544876836381174527200297540561298613916203860 371 | c1: c0: c1: 372 | 8164735751726867362664406806290871136633702655186802416211482152428240187062 373 | c1: c1: c0: 374 | 2 375 | c1: c1: c1: 376 | 0 377 | c1: c2: c0: 378 | 0 379 | c1: c2: c1: 380 | 0*/ 381 | 382 | /*it('Test ell', function() { 383 | console.log(""); 384 | 385 | let f_test = Fq12.one().add(Fq12.one()); 386 | let coeff_test = G2.generator(); 387 | let p_test = G1.generator().to_affine(); 388 | 389 | let f_res = Pairing.ell(f_test, coeff_test, p_test); 390 | 391 | console.log("The multiplication result is:"); 392 | console.log(f_res.c0.c0.c0.toBigInt()); 393 | console.log(f_res.c0.c0.c1.toBigInt()); 394 | console.log(f_res.c0.c1.c0.toBigInt()); 395 | console.log(f_res.c0.c1.c1.toBigInt()); 396 | console.log(f_res.c0.c2.c0.toBigInt()); 397 | console.log(f_res.c0.c2.c1.toBigInt()); 398 | console.log(f_res.c1.c0.c0.toBigInt()); 399 | console.log(f_res.c1.c0.c1.toBigInt()); 400 | console.log(f_res.c1.c1.c0.toBigInt()); 401 | console.log(f_res.c1.c1.c1.toBigInt()); 402 | console.log(f_res.c1.c2.c0.toBigInt()); 403 | console.log(f_res.c1.c2.c1.toBigInt()); 404 | 405 | }); 406 | 407 | /*Result of the miller loop is: 408 | c0: c0: c0: 409 | 8435349465297435165939613326182510559432768151171456927563845943835587893318 410 | c0: c0: c1: 411 | 6922971044582888302935485344122945678712627252066050934761503002215637833398 412 | c0: c1: c0: 413 | 3020546541473938793128002451374960532067818205039443099811129595927388067286 414 | c0: c1: c1: 415 | 17769323050513707778517677686953418267091010046392128507544477374469625612984 416 | c0: c2: c0: 417 | 3763732934528536011745626858778706370427043921669046010442849159497712700772 418 | c0: c2: c1: 419 | 14549845357758960899323156041109965068703251629332557195387415594452856987644 420 | c1: c0: c0: 421 | 6794473403739122020442363891712360649335653313810088419703280842965192069511 422 | c1: c0: c1: 423 | 13392128610088202061854730384851289230662074442107826208219257402048685222537 424 | c1: c1: c0: 425 | 7433825691721511851102122167239491011947119642840494065360783975919138076820 426 | c1: c1: c1: 427 | 19219766045438315144692585480887046659586273909639508979936361306434866171983 428 | c1: c2: c0: 429 | 21644873758654527024745287033018303248224386386103324977073303408472355346721 430 | c1: c2: c1: 431 | 1280249797837326183721155126067164609135389664909150424992007507737623690374*/ 432 | 433 | it('Test miller loop', function() { 434 | console.log("test miller loop on G2(2G) and G1(3G)"); 435 | 436 | let g1_affine_3g = new G1Affine( 437 | new Fq(3353031288059533942658390886683067124040920775575537747144343083137631628272n), 438 | new Fq(19321533766552368860946552437480515441416830039777911637913418824951667761761n) 439 | ) 440 | 441 | let g2_affine_2g = new G2Affine( 442 | new Fq2( 443 | new Fq(18029695676650738226693292988307914797657423701064905010927197838374790804409n), 444 | new Fq(14583779054894525174450323658765874724019480979794335525732096752006891875705n) 445 | ), 446 | 447 | new Fq2( 448 | new Fq(2140229616977736810657479771656733941598412651537078903776637920509952744750n), 449 | new Fq(11474861747383700316476719153975578001603231366361248090558603872215261634898n) 450 | ) 451 | ); 452 | 453 | let miller_loop_test = Pairing.miller_loop(g2_affine_2g, g1_affine_3g); 454 | console.log("miller loop result"); 455 | console.log(miller_loop_test.c0.c0.c0.toBigInt()); 456 | console.log(miller_loop_test.c0.c0.c1.toBigInt()); 457 | console.log(miller_loop_test.c0.c1.c0.toBigInt()); 458 | console.log(miller_loop_test.c0.c1.c1.toBigInt()); 459 | console.log(miller_loop_test.c0.c2.c0.toBigInt()); 460 | console.log(miller_loop_test.c0.c2.c1.toBigInt()); 461 | console.log(miller_loop_test.c1.c0.c0.toBigInt()); 462 | console.log(miller_loop_test.c1.c0.c1.toBigInt()); 463 | console.log(miller_loop_test.c1.c1.c0.toBigInt()); 464 | console.log(miller_loop_test.c1.c1.c1.toBigInt()); 465 | console.log(miller_loop_test.c1.c2.c0.toBigInt()); 466 | console.log(miller_loop_test.c1.c2.c1.toBigInt()); 467 | 468 | }); 469 | 470 | it('Bilinearity test 1', function() { 471 | console.log("test miller loop on G2 and G1 generator"); 472 | 473 | let a = G1.generator(); 474 | let b = G2.generator(); 475 | 476 | let ac = a.add(a).add(a).add(a); 477 | let ad = a.add(a).add(a); 478 | 479 | let bc = b.add(b).add(b).add(b); 480 | let bd = b.add(b).add(b); 481 | 482 | let acbd = Pairing.pair(bd.to_affine(), ac.to_affine()); 483 | let adbc = Pairing.pair(bc.to_affine(), ad.to_affine()); 484 | 485 | console.log("Bilinearity test...") 486 | console.log(acbd.c0.c0.c0.toBigInt()); 487 | console.log(adbc.c0.c0.c0.toBigInt()); 488 | }); 489 | 490 | 491 | it('Bilinearity test 2', function() { 492 | console.log("test miller loop on G2 and G1 generator"); 493 | 494 | let a = G1.generator(); 495 | let b = G2.generator(); 496 | 497 | let ac = a.add(a).add(a).add(a).add(a); 498 | let ad = a.add(a).add(a); 499 | 500 | let bc = b.add(b).add(b).add(b).add(b); 501 | let bd = b.add(b).add(b); 502 | 503 | let acbd = Pairing.pair(bd.to_affine(), ac.to_affine()); 504 | let adbc = Pairing.pair(bc.to_affine(), ad.to_affine()); 505 | 506 | console.log("Bilinearity test...") 507 | console.log(acbd.c0.c0.c0.toBigInt()); 508 | console.log(adbc.c0.c0.c0.toBigInt()); 509 | }); 510 | 511 | // e(P, Q + R) = e(P, Q) * e(P, R) 512 | it('Bilinearity test 2', function() { 513 | console.log("test miller loop on G2 and G1 generator"); 514 | 515 | let P = G1.generator(); 516 | let Q = G2.generator(); 517 | 518 | let p_q_plus_r = Pairing.pair(Q.add(Q).to_affine(), P.to_affine()); 519 | let p_q = Pairing.pair(Q.to_affine(), P.to_affine()); 520 | let p_r = Pairing.pair(Q.to_affine(), P.to_affine()); 521 | 522 | let p_q_mul_p_r = p_q.mul(p_r); 523 | 524 | console.log("Bilinearity test...") 525 | console.log("e(P, Q + R) is: "); 526 | console.log(p_q_plus_r.c0.c0.c0.toBigInt()); 527 | console.log(p_q_plus_r.c0.c0.c1.toBigInt()); 528 | console.log(p_q_plus_r.c0.c1.c0.toBigInt()); 529 | console.log(p_q_plus_r.c0.c1.c1.toBigInt()); 530 | console.log(p_q_plus_r.c0.c2.c0.toBigInt()); 531 | console.log(p_q_plus_r.c0.c2.c1.toBigInt()); 532 | console.log(p_q_plus_r.c1.c0.c0.toBigInt()); 533 | console.log(p_q_plus_r.c1.c0.c1.toBigInt()); 534 | console.log(p_q_plus_r.c1.c1.c0.toBigInt()); 535 | console.log(p_q_plus_r.c1.c1.c1.toBigInt()); 536 | console.log(p_q_plus_r.c1.c2.c0.toBigInt()); 537 | console.log(p_q_plus_r.c1.c2.c1.toBigInt()); 538 | 539 | console.log("e(P, Q) * e(P, R)"); 540 | console.log(p_q_mul_p_r.c0.c0.c0.toBigInt()); 541 | console.log(p_q_mul_p_r.c0.c0.c1.toBigInt()); 542 | console.log(p_q_mul_p_r.c0.c1.c0.toBigInt()); 543 | console.log(p_q_mul_p_r.c0.c1.c1.toBigInt()); 544 | console.log(p_q_mul_p_r.c0.c2.c0.toBigInt()); 545 | console.log(p_q_mul_p_r.c0.c2.c1.toBigInt()); 546 | console.log(p_q_mul_p_r.c1.c0.c0.toBigInt()); 547 | console.log(p_q_mul_p_r.c1.c0.c1.toBigInt()); 548 | console.log(p_q_mul_p_r.c1.c1.c0.toBigInt()); 549 | console.log(p_q_mul_p_r.c1.c1.c1.toBigInt()); 550 | console.log(p_q_mul_p_r.c1.c2.c0.toBigInt()); 551 | console.log(p_q_mul_p_r.c1.c2.c1.toBigInt()); 552 | }); 553 | 554 | }); --------------------------------------------------------------------------------