├── src ├── subtractTensor.circom ├── where.circom ├── rateOfChange.circom ├── calculatedScoreFraction.circom ├── integerDivision.circom ├── finalNewScore.circom ├── distanceFromScore.circom ├── proofSizeRewardMetric.circom ├── metricNormalized.circom ├── responseTimeNormalized.circom ├── clampTensor.circom ├── incentiveMetric.circom ├── responseTimeMetric.circom └── circuit.circom ├── .gitignore └── README.md /src/subtractTensor.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | template Subtract(){ 4 | signal input a; 5 | signal input b; 6 | signal output c; 7 | c <== (a - b); 8 | } 9 | -------------------------------------------------------------------------------- /src/where.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | template Where(){ 4 | 5 | signal input selector; 6 | signal input choices[2]; 7 | signal output out; 8 | signal temp_signal_1; 9 | signal temp_signal_2; 10 | selector*(1-selector) === 0; 11 | 12 | temp_signal_1 <== choices[0] * selector; 13 | temp_signal_2 <== choices[1] * (1 - selector); 14 | out <== (temp_signal_1 + temp_signal_2)*1; 15 | } 16 | -------------------------------------------------------------------------------- /src/rateOfChange.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "./where.circom"; 4 | 5 | template RateOfChange(){ 6 | signal input verified; 7 | signal input RATE_OF_RECOVERY; 8 | signal input RATE_OF_DECAY; 9 | signal output out; 10 | component where; 11 | 12 | where = Where(); 13 | where.selector <== verified; 14 | where.choices[0] <== RATE_OF_RECOVERY; 15 | where.choices[1] <== RATE_OF_DECAY; 16 | out <== where.out; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.so 6 | .Python 7 | build/ 8 | develop-eggs/ 9 | dist/ 10 | downloads/ 11 | eggs/ 12 | .eggs/ 13 | lib/ 14 | lib64/ 15 | parts/ 16 | sdist/ 17 | var/ 18 | wheels/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | .env 23 | venv/ 24 | ENV/ 25 | 26 | # Node 27 | node_modules/ 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .npm 32 | .yarn-integrity 33 | 34 | # IDE 35 | .idea/ 36 | .vscode/ 37 | *.swp 38 | *.swo 39 | .DS_Store 40 | 41 | # Project specific 42 | *.pt 43 | *.pth 44 | *.onnx 45 | *.png 46 | *.jpg 47 | *.jpeg 48 | *.log 49 | .cache/ 50 | temp-input.json 51 | *.ptau 52 | .python-version 53 | out/ 54 | -------------------------------------------------------------------------------- /src/calculatedScoreFraction.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | include "./subtractTensor.circom"; 3 | include "./clampTensor.circom"; 4 | include "./integerDivision.circom"; 5 | 6 | template CalculatedScoreFraction(b){ 7 | signal input response_time_reward_metric; 8 | signal input proof_size_reward_metric; 9 | signal input competition_weighted; 10 | signal input scaling; 11 | signal output out; 12 | 13 | signal total; 14 | total <== response_time_reward_metric + proof_size_reward_metric + competition_weighted; 15 | 16 | component clamp = Clamp(b); 17 | clamp.val <== total; 18 | clamp.min <== 0; 19 | clamp.max <== scaling; 20 | 21 | out <== clamp.out; 22 | } 23 | -------------------------------------------------------------------------------- /src/integerDivision.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | include "./clampTensor.circom"; 3 | 4 | 5 | template IsZero() { 6 | signal input in; 7 | signal output out; 8 | 9 | signal inv <-- in != 0 ? 1 / in : 0; 10 | out <== 1 - (in * inv); 11 | 12 | in * out === 0; 13 | } 14 | 15 | template IntDiv(n) { 16 | signal input in[2]; 17 | signal output out; 18 | 19 | signal is_non_zero <== IsZero()(in[1]); 20 | 0 === is_non_zero; 21 | 22 | var quot_hint = in[0] \ in[1]; 23 | var rem_hint = in[0] % in[1]; 24 | signal quot <-- quot_hint; 25 | signal rem <-- rem_hint; 26 | in[0] === quot * in[1] + rem; 27 | 28 | _ <== Num2Bits(n)(quot); 29 | _ <== Num2Bits(n)(rem); 30 | _ <== Num2Bits(n)(in[1]); 31 | 32 | signal rem_is_valid <== LessThan(n)([rem, in[1]]); 33 | 1 === rem_is_valid; 34 | 35 | out <== quot; 36 | } 37 | -------------------------------------------------------------------------------- /src/finalNewScore.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "./where.circom"; 4 | 5 | 6 | template FinalNewScore(){ 7 | 8 | signal input verified; 9 | signal input previous_score; 10 | signal input change_in_score; 11 | signal input is_positive_change_in_score; 12 | signal output new_score; 13 | 14 | signal temp_sub; 15 | signal temp_add; 16 | signal temp_add_pos; 17 | signal temp_add_neg; 18 | 19 | component where; 20 | temp_sub <== (previous_score - change_in_score)*1; 21 | 22 | 23 | temp_add_pos <== (previous_score + change_in_score)*is_positive_change_in_score; 24 | temp_add_neg <== (previous_score - change_in_score)*(1 - is_positive_change_in_score); 25 | temp_add <== temp_add_pos + temp_add_neg; 26 | 27 | where = Where(); 28 | where.selector <== verified; 29 | where.choices[0] <== temp_add; 30 | where.choices[1] <== temp_sub; 31 | new_score <== where.out; 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proof of Weights for Subnet 2 2 | 3 | This repo contains source files for the circom implementation of Subnet 2's incentive mechanism. 4 | 5 | ## Steps to reproduce output 6 | 7 | ### 1. Adjust the `batch_size` in `src/circuit.circom` 8 | 9 | The last line in this file appears as: 10 | 11 | ```circom 12 | ]} = IncentiveMechanism(1024,40); 13 | ``` 14 | 15 | To generate the circuit for a different batch size, you need to change the first argument to the `IncentiveMechanism` component (for example `256` for SN2 PoW 256). 16 | 17 | ### Run circom to export the circuit 18 | 19 | This will provide the WASM, raw R1CS, witness generation code, symbols and C code for the circuit. 20 | 21 | ```bash 22 | circom --r1cs --wasm --c --sym --inspect circuit.circom 23 | ``` 24 | 25 | If successful, you should see the following output: 26 | 27 | ```log 28 | Written successfully: ./circuit.r1cs 29 | Written successfully: ./circuit.sym 30 | Written successfully: ./circuit_cpp/circuit.cpp and ./circuit_cpp/circuit.dat 31 | Written successfully: ./circuit_cpp/main.cpp, circom.hpp, calcwit.hpp, calcwit.cpp, fr.hpp, fr.cpp, fr.asm and Makefile 32 | Written successfully: ./circuit_js/circuit.wasm 33 | Everything went okay 34 | ``` 35 | -------------------------------------------------------------------------------- /src/distanceFromScore.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "./where.circom"; 4 | include "./clampTensor.circom"; 5 | 6 | template DistanceFromScore(b){ 7 | 8 | signal input verified; 9 | signal input maximum_score; 10 | signal input previous_score; 11 | signal output distanceFromScore; 12 | signal output isPos; 13 | 14 | signal temp_sub; 15 | signal temp_sub_2; 16 | 17 | component n2b_previous_score; 18 | component n2b_maximum_score; 19 | component where; 20 | component positive; 21 | 22 | n2b_previous_score = Num2Bits(b); 23 | n2b_previous_score.in <== previous_score; 24 | n2b_maximum_score = Num2Bits(b); 25 | n2b_maximum_score.in <== maximum_score; 26 | 27 | positive = LessThan(b); 28 | positive.in[0] <== previous_score; 29 | positive.in[1] <== maximum_score; 30 | isPos <== positive.out; 31 | 32 | temp_sub <== (maximum_score - previous_score)*isPos; 33 | temp_sub_2 <== (previous_score - maximum_score)*(1 - isPos); 34 | 35 | where = Where(); 36 | where.selector <== verified; 37 | where.choices[0] <== temp_sub + temp_sub_2; 38 | where.choices[1] <== previous_score; 39 | distanceFromScore <== where.out; 40 | } 41 | -------------------------------------------------------------------------------- /src/proofSizeRewardMetric.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | include "./subtractTensor.circom"; 3 | include "./clampTensor.circom"; 4 | include "./integerDivision.circom"; 5 | 6 | template ProofSizeRewardMetric(b){ 7 | signal input PROOF_SIZE_WEIGHT; 8 | signal input proof_size; 9 | signal input PROOF_SIZE_THRESHOLD; 10 | signal input scaling; 11 | signal output proof_size_reward_metric; 12 | signal division; 13 | signal remainder; 14 | signal pos; 15 | signal temp_scale; 16 | signal temp_mul; 17 | signal temp_max1; 18 | signal temp_max2; 19 | signal temp_clamp; 20 | component clamp; 21 | component int_div; 22 | component int_div_2; 23 | component less_than; 24 | 25 | temp_scale <== proof_size * scaling; 26 | 27 | int_div = IntDiv(b); 28 | int_div.in[0] <== temp_scale; 29 | int_div.in[1] <== PROOF_SIZE_THRESHOLD; 30 | division <== int_div.out; 31 | 32 | clamp = Clamp(b); 33 | clamp.val <== division; 34 | clamp.min <== 0; 35 | clamp.max <== scaling; 36 | 37 | temp_mul <== PROOF_SIZE_WEIGHT * clamp.out; 38 | 39 | int_div_2 = IntDiv(b); 40 | int_div_2.in[0] <== temp_mul; 41 | int_div_2.in[1] <== scaling; 42 | proof_size_reward_metric <== int_div_2.out; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/metricNormalized.circom: -------------------------------------------------------------------------------- 1 | include "./subtractTensor.circom"; 2 | include "./integerDivision.circom"; 3 | 4 | template MetricNormalized(b) { 5 | // Input signals 6 | signal input value; 7 | signal input minimum_value; 8 | signal input maximum_value; 9 | signal input MAXIMUM_VALUE_DECIMAL; 10 | signal input scaling; 11 | signal output out; 12 | 13 | // Components 14 | component subtract1 = Subtract(); 15 | component subtract2 = Subtract(); 16 | component division = IntDiv(b); 17 | component num2Bits = Num2Bits(b); 18 | component lessThan = LessThan(b); 19 | 20 | // Calculate normalized value: (value - min) * scaling / (max - min) 21 | subtract1.a <== value; 22 | subtract1.b <== minimum_value; 23 | 24 | subtract2.a <== maximum_value; 25 | subtract2.b <== minimum_value; 26 | 27 | division.in[0] <== subtract1.c * scaling; 28 | division.in[1] <== subtract2.c; 29 | 30 | num2Bits.in <== MAXIMUM_VALUE_DECIMAL; 31 | 32 | // Clamp result to MAXIMUM_VALUE_DECIMAL 33 | lessThan.in[0] <== MAXIMUM_VALUE_DECIMAL; 34 | lessThan.in[1] <== division.out; 35 | 36 | // Select between computed value and maximum based on comparison 37 | out <== division.out * (1 - lessThan.out) + MAXIMUM_VALUE_DECIMAL * lessThan.out; 38 | } 39 | -------------------------------------------------------------------------------- /src/responseTimeNormalized.circom: -------------------------------------------------------------------------------- 1 | 2 | pragma circom 2.0.0; 3 | include "./subtractTensor.circom"; 4 | include "./clampTensor.circom"; 5 | include "./integerDivision.circom"; 6 | 7 | 8 | template ResponseTimeNormalized(b){ 9 | signal input response_time; 10 | signal input minimum_response_time; 11 | signal input maximum_response_time; 12 | signal input MAXIMUM_RESPONSE_TIME_DECIMAL; 13 | signal input scaling; 14 | signal output out; 15 | component subtract1; 16 | component subtract2; 17 | component division; 18 | component Num2Bits; 19 | component LessThan; 20 | component clamp; 21 | 22 | signal temp_1[2]; 23 | 24 | subtract1 = Subtract(); 25 | subtract1.a <== response_time; 26 | subtract1.b <== minimum_response_time; 27 | 28 | subtract2 = Subtract(); 29 | subtract2.a <== maximum_response_time; 30 | subtract2.b <== minimum_response_time; 31 | 32 | division = IntDiv(b); 33 | division.in[0] <== subtract1.c*scaling; 34 | division.in[1] <== subtract2.c; 35 | 36 | Num2Bits = Num2Bits(b); 37 | Num2Bits.in <== MAXIMUM_RESPONSE_TIME_DECIMAL; 38 | 39 | LessThan = LessThan(b); 40 | LessThan.in[0] <== MAXIMUM_RESPONSE_TIME_DECIMAL; 41 | LessThan.in[1] <== division.out; 42 | 43 | temp_1[0] <== division.out * (1 - LessThan.out); 44 | temp_1[1] <== MAXIMUM_RESPONSE_TIME_DECIMAL * LessThan.out; 45 | out <== temp_1[0] + temp_1[1]; 46 | } -------------------------------------------------------------------------------- /src/clampTensor.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | template Num2Bits(n) { 4 | assert(n < 254); 5 | signal input in; 6 | signal output out[n]; 7 | 8 | var lc = 0; 9 | var bit_value = 1; 10 | 11 | for (var i = 0; i < n; i++) { 12 | out[i] <-- (in >> i) & 1; 13 | AssertBit()(out[i]); 14 | 15 | lc += out[i] * bit_value; 16 | bit_value <<= 1; 17 | } 18 | 19 | lc === in; 20 | } 21 | template AssertBit() { 22 | signal input in; 23 | 24 | in * (in - 1) === 0; 25 | } 26 | 27 | template LessThan(n) { 28 | assert(n <= 252); 29 | signal input in[2]; 30 | signal output out; 31 | 32 | component toBits = Num2Bits(n+1); 33 | toBits.in <== ((1 << n) + in[0]) - in[1]; 34 | 35 | out <== 1 - toBits.out[n]; 36 | } 37 | 38 | template Clamp(b){ 39 | signal input val; 40 | signal input min; 41 | signal input max; 42 | signal output out; 43 | signal temp_max; 44 | signal temp_min; 45 | signal temp_1[2]; 46 | signal temp_2[2]; 47 | 48 | component Num2Bits[4]; 49 | component LessThan[2]; 50 | 51 | Num2Bits[0] = Num2Bits(b); 52 | Num2Bits[1] = Num2Bits(b); 53 | Num2Bits[2] = Num2Bits(b); 54 | Num2Bits[3] = Num2Bits(b); 55 | 56 | Num2Bits[0].in <== val; 57 | Num2Bits[1].in <== min; 58 | Num2Bits[2].in <== max; 59 | 60 | LessThan[0] = LessThan(b); 61 | LessThan[1] = LessThan(b); 62 | 63 | LessThan[0].in[0] <== val; 64 | LessThan[0].in[1] <== min; 65 | temp_1[0] <== val * (1 - LessThan[0].out); 66 | temp_2[0] <== min * LessThan[0].out; 67 | temp_max <== temp_1[0] + temp_2[0]; 68 | 69 | Num2Bits[3].in <== temp_max; 70 | 71 | 72 | LessThan[1].in[0] <== max; 73 | LessThan[1].in[1] <== temp_max; 74 | 75 | temp_1[1] <== temp_max * (1 - LessThan[1].out); 76 | temp_2[1] <== max * LessThan[1].out; 77 | temp_min <== temp_1[1] + temp_2[1]; 78 | 79 | out <== temp_min*1; 80 | } 81 | 82 | template clampTensor (n, b) { 83 | var i; 84 | 85 | signal input val[n]; 86 | signal input min[n]; 87 | signal input max[n]; 88 | signal output out[n]; 89 | component comp[n]; 90 | 91 | for (i=0; i