├── src ├── bridge │ ├── mod.rs │ ├── graph.rs │ └── client.rs ├── signatures │ ├── mod.rs │ ├── winternitz_hash.rs │ ├── winternitz.rs │ └── winternitz_compact.rs ├── fflonk │ ├── circom_ref │ │ ├── public.json │ │ ├── test_circuit.circom │ │ ├── input.json │ │ ├── verification_key.json │ │ └── proof.json │ ├── mod.rs │ ├── compute_e.rs │ ├── compute_pi.rs │ ├── compute_j.rs │ ├── compute_lagrange.rs │ ├── compute_f.rs │ ├── checkpairing_normalize.rs │ ├── checkpairing_a1.rs │ ├── checkpairing_zerotest.rs │ ├── check_format.rs │ ├── checkpairing_miller_loop.rs │ ├── compute_fej_scalars.rs │ ├── compute_c_wi.rs │ ├── compute_r1.rs │ └── compute_r0.rs ├── groth16 │ ├── mod.rs │ ├── constants.rs │ ├── test.rs │ └── verifier.rs ├── hash │ └── mod.rs ├── u32 │ ├── mod.rs │ ├── u32_zip.rs │ ├── u32_add.rs │ ├── u32_and.rs │ ├── u32_or.rs │ ├── u32_rshift.rs │ ├── u32_std.rs │ ├── u32_rrot.rs │ └── u32_xor.rs ├── u4 │ ├── mod.rs │ ├── u4_rot_stack.rs │ ├── u4_shift_stack.rs │ ├── u4_std.rs │ ├── u4_shift.rs │ ├── u4_logic_stack.rs │ ├── u4_rot.rs │ └── u4_add_stack.rs ├── bn254 │ ├── mod.rs │ └── msm.rs ├── bigint │ ├── mod.rs │ ├── mul.rs │ ├── sub.rs │ └── add.rs ├── pseudo.rs └── lib.rs ├── .rustfmt.toml ├── .gitignore ├── README.md └── Cargo.toml /src/bridge/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod graph; 3 | pub mod transactions; 4 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | fn_single_line = true 2 | ignore = [ 3 | "src/utils/merkle.rs", 4 | ] 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/signatures/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod winternitz; 2 | pub mod winternitz_compact; 3 | pub mod winternitz_hash; 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/fflonk/circom_ref/public.json: -------------------------------------------------------------------------------- 1 | [ 2 | "246513590391103489634602289097178521809", 3 | "138371009144214353742010089705444713455" 4 | ] -------------------------------------------------------------------------------- /src/groth16/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod offchain_checker; 3 | 4 | 5 | #[cfg(test)] 6 | mod test; 7 | pub mod verifier; 8 | -------------------------------------------------------------------------------- /src/hash/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod blake3; 2 | //pub mod blake3_u4; 3 | pub mod sha256; 4 | pub mod sha256_u4; 5 | //pub mod sha256_u4_stack; 6 | -------------------------------------------------------------------------------- /src/u32/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod u32_add; 2 | pub mod u32_and; 3 | pub mod u32_or; 4 | pub mod u32_rrot; 5 | pub mod u32_rshift; 6 | pub mod u32_std; 7 | pub mod u32_xor; 8 | pub mod u32_zip; 9 | -------------------------------------------------------------------------------- /src/u4/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod u4_add; 2 | //pub mod u4_add_stack; 3 | pub mod u4_logic; 4 | //pub mod u4_logic_stack; 5 | pub mod u4_rot; 6 | //pub mod u4_rot_stack; 7 | pub mod u4_shift; 8 | //pub mod u4_shift_stack; 9 | pub mod u4_std; 10 | -------------------------------------------------------------------------------- /src/bn254/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fq; 2 | pub mod fq12; 3 | pub mod fq2; 4 | pub mod fq6; 5 | pub mod fr; 6 | 7 | pub mod curves; 8 | 9 | pub mod pairing; 10 | 11 | pub mod ell_coeffs; 12 | 13 | pub mod fp254impl; 14 | pub mod msm; 15 | pub mod utils; 16 | -------------------------------------------------------------------------------- /src/fflonk/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod check_format; 2 | pub mod checkpairing_a1; 3 | pub mod checkpairing_miller_loop; 4 | pub mod checkpairing_normalize; 5 | pub mod checkpairing_with_c_wi; 6 | pub mod checkpairing_zerotest; 7 | pub mod compute_c_wi; 8 | pub mod compute_challenges; 9 | pub mod compute_e; 10 | pub mod compute_f; 11 | pub mod compute_fej_scalars; 12 | pub mod compute_inversions; 13 | pub mod compute_j; 14 | pub mod compute_lagrange; 15 | pub mod compute_pi; 16 | pub mod compute_r0; 17 | pub mod compute_r1; 18 | pub mod compute_r2; 19 | pub mod verifier; 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | 17 | # Added by cargo 18 | 19 | /target 20 | 21 | .idea 22 | .vscode 23 | 24 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitVM: Smarter Bitcoin Contracts 2 | 3 | The official implementation of [BitVM2](https://bitvm.org/bitvm2), running a [SNARK verifier](https://bitvm.org/snark). Work in progress. 4 | 5 | We are following the implementation of [Arkworks](https://github.com/arkworks-rs) 6 | 7 | 8 | ## Overview 9 | 10 | - Winternitz signatures 11 | - BigInt arithmetic 12 | - Bn254 13 | - Field operations 14 | - Extension fields 15 | - Curve operations 16 | - Pairings 17 | - Fflonk verifier 18 | - Groth16 verifier 19 | 20 | 21 | 22 | [BitVM1](https://github.com/BitVM/BitVM/tree/1dce989d1963b90c35391b77b451c6823302d503) 23 | -------------------------------------------------------------------------------- /src/bigint/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add; 2 | pub mod bits; 3 | pub mod cmp; 4 | pub mod inv; 5 | pub mod mul; 6 | pub mod std; 7 | pub mod sub; 8 | pub mod u29x9; 9 | 10 | pub struct BigIntImpl {} 11 | 12 | impl BigIntImpl { 13 | pub const N_BITS: u32 = N_BITS; 14 | pub const N_LIMBS: u32 = (N_BITS + LIMB_SIZE - 1) / LIMB_SIZE; 15 | pub const HEAD: u32 = N_BITS - (Self::N_LIMBS - 1) * LIMB_SIZE; 16 | pub const HEAD_OFFSET: u32 = 1u32 << Self::HEAD; 17 | } 18 | 19 | pub type U254 = BigIntImpl<254, 29>; // 30? 20 | pub type U64 = BigIntImpl<64, 16>; 21 | -------------------------------------------------------------------------------- /src/groth16/constants.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use crate::bn254::{fp254impl::Fp254Impl, fq::Fq}; 4 | use num_bigint::BigUint; 5 | use num_traits::Num; 6 | use once_cell::sync::Lazy; 7 | 8 | pub static P_POW3: Lazy = 9 | Lazy::new(|| BigUint::from_str_radix(Fq::MODULUS, 16).unwrap().pow(3_u32)); 10 | 11 | pub static LAMBDA: Lazy = Lazy::new(|| { 12 | BigUint::from_str( 13 | "10486551571378427818905133077457505975146652579011797175399169355881771981095211883813744499745558409789005132135496770941292989421431235276221147148858384772096778432243207188878598198850276842458913349817007302752534892127325269" 14 | ).unwrap() 15 | }); 16 | -------------------------------------------------------------------------------- /src/fflonk/circom_ref/test_circuit.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "circomlib/circuits/sha256/sha256.circom"; 4 | include "circomlib/circuits/bitify.circom"; 5 | 6 | template Main() { 7 | signal input in[256]; // private 8 | 9 | signal output out_1; 10 | signal output out_2; 11 | 12 | component sha256 = Sha256(256); 13 | sha256.in <== in; 14 | 15 | component b2n_1 = Bits2Num(128); 16 | for(var i = 0; i < 128; i++) { 17 | b2n_1.in[i] <== sha256.out[i]; 18 | } 19 | out_1 <== b2n_1.out; 20 | 21 | component b2n_2 = Bits2Num(128); 22 | for(var i = 0; i < 128; i++) { 23 | b2n_2.in[i] <== sha256.out[128 + i]; 24 | } 25 | out_2 <== b2n_2.out; 26 | } 27 | 28 | component main = Main(); -------------------------------------------------------------------------------- /src/fflonk/circom_ref/input.json: -------------------------------------------------------------------------------- 1 | { "in": [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0] } -------------------------------------------------------------------------------- /src/fflonk/circom_ref/verification_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "fflonk", 3 | "curve": "bn128", 4 | "nPublic": 2, 5 | "power": 18, 6 | "k1": "2", 7 | "k2": "3", 8 | "w": "11699596668367776675346610687704220591435078791727316319397053191800576917728", 9 | "w3": "21888242871839275217838484774961031246154997185409878258781734729429964517155", 10 | "w4": "21888242871839275217838484774961031246007050428528088939761107053157389710902", 11 | "w8": "19540430494807482326159819597004422086093766032135589407132600596362845576832", 12 | "wr": "19699792133865984655632994927951174943026102279822605383822362801478354085676", 13 | "X_2": [ 14 | [ 15 | "21831381940315734285607113342023901060522397560371972897001948545212302161822", 16 | "17231025384763736816414546592865244497437017442647097510447326538965263639101" 17 | ], 18 | [ 19 | "2388026358213174446665280700919698872609886601280537296205114254867301080648", 20 | "11507326595632554467052522095592665270651932854513688777769618397986436103170" 21 | ], 22 | [ 23 | "1", 24 | "0" 25 | ] 26 | ], 27 | "C0": [ 28 | "303039279492065453055049758769758984569666029850327527958551993331680103359", 29 | "15061669176783843627135305167141360334623983780813847469326507992811672859575", 30 | "1" 31 | ] 32 | } -------------------------------------------------------------------------------- /src/fflonk/compute_e.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::curves::G1Projective; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fr::Fr; 7 | use crate::treepp::*; 8 | 9 | #[test] 10 | fn test_compute_e() { 11 | let script = script! { 12 | // push G1x, G1y (3 elements) 13 | { Fq::push_dec("1") } 14 | { Fq::push_dec("2") } 15 | { Fq::push_dec("1") } 16 | 17 | // push the scalar 18 | { Fr::push_dec("20939596453786382856662891660365666437489374655427796935463148514894213437967") } 19 | { G1Projective::scalar_mul() } 20 | 21 | { Fq::push_dec("10905825615646575916826598897124608361270584984190374057529352166783343482862") } 22 | { Fq::push_dec("19290909793509893735943189519527824156597590461000288988451227768509803549366") } 23 | { Fq::push_dec("10334981607594421347972269000738063023881743479366183631046354259553646162574") } 24 | 25 | { G1Projective::equalverify() } 26 | OP_TRUE 27 | }; 28 | 29 | println!("fflonk.compute_e = {} bytes", script.len()); 30 | 31 | let exec_result = execute_script(script); 32 | assert!(exec_result.success); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/fflonk/compute_pi.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::fp254impl::Fp254Impl; 4 | use crate::bn254::fr::Fr; 5 | use crate::treepp::*; 6 | 7 | #[test] 8 | fn test_compute_pi() { 9 | let script = script! { 10 | // push L[1], L[2] 11 | { Fr::push_dec("19264250262515049392118907974032894668050943806280011767302681470321758079402") } 12 | { Fr::push_dec("5147149846110622280763906966379810308773882279335494056719681880590330080749") } 13 | 14 | // push the inputs 15 | { Fr::push_dec("246513590391103489634602289097178521809") } 16 | { Fr::push_dec("138371009144214353742010089705444713455") } 17 | 18 | { Fr::roll(2) } 19 | { Fr::mul() } 20 | { Fr::toaltstack() } 21 | 22 | { Fr::mul() } 23 | { Fr::fromaltstack() } 24 | { Fr::add(1, 0) } 25 | { Fr::neg(0) } 26 | 27 | { Fr::push_dec("12368363170870087162509434874521168463460384615249055347885673275750149676873") } 28 | { Fr::equalverify(1, 0) } 29 | OP_TRUE 30 | }; 31 | 32 | println!("fflonk.compute_pi = {} bytes", script.len()); 33 | 34 | let exec_result = execute_script(script); 35 | assert!(exec_result.success); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/fflonk/compute_j.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::curves::G1Projective; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fr::Fr; 7 | use crate::treepp::*; 8 | 9 | #[test] 10 | fn test_compute_j() { 11 | let script = script! { 12 | // push W1 (3 elements) 13 | { Fq::push_dec("32650538602400348219903702316313439265244325226254563471430382441955222030") } 14 | { Fq::push_dec("1102261574488401129043229793384018650738538286437537952751903719159654317199") } 15 | { Fq::push_dec("1") } 16 | 17 | // push the scalar 18 | { Fr::push_dec("1021979267781513382639867303596638615172285308777215242749714941672007413081") } 19 | { G1Projective::scalar_mul() } 20 | 21 | { Fq::push_dec("2959562071167086018427906252728568621973040394868315776950851582459669551081") } 22 | { Fq::push_dec("5248835691815263544471788309691308785423871173394577194626050104765380585421") } 23 | { Fq::push_dec("19277062899702791882368245424983329716198384271778017207570439921049817477033") } 24 | 25 | { G1Projective::equalverify() } 26 | OP_TRUE 27 | }; 28 | 29 | println!("fflonk.compute_j = {} bytes", script.len()); 30 | 31 | let exec_result = execute_script(script); 32 | assert!(exec_result.success); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/u32/u32_zip.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use crate::treepp::{script, Script}; 3 | 4 | /// Zip the top two u32 elements 5 | /// input: a0 a1 a2 a3 b0 b1 b2 b3 6 | /// output: a0 b0 a1 b1 a2 b2 a3 b3 7 | pub fn u32_zip(mut a: u32, mut b: u32) -> Script { 8 | if a > b { 9 | (a, b) = (b, a); 10 | } 11 | 12 | a = (a + 1) * 4 - 1; 13 | b = (b + 1) * 4 - 1; 14 | 15 | script! { 16 | {a} OP_ROLL {b} OP_ROLL 17 | {a+1} OP_ROLL {b} OP_ROLL 18 | {a+2} OP_ROLL {b} OP_ROLL 19 | {a+3} OP_ROLL {b} OP_ROLL 20 | } 21 | } 22 | 23 | /// Copy and zip the top two u32 elements 24 | /// input: a0 a1 a2 a3 b0 b1 b2 b3 25 | /// output: a0 b0 a1 b1 a2 b2 a3 b3 a0 a1 a2 a3 26 | pub fn u32_copy_zip(a: u32, b: u32) -> Script { 27 | if a < b { 28 | _u32_copy_zip(a, b) 29 | } else { 30 | _u32_zip_copy(b, a) 31 | } 32 | } 33 | 34 | pub fn _u32_copy_zip(mut a: u32, mut b: u32) -> Script { 35 | assert!(a < b); 36 | 37 | a = (a + 1) * 4 - 1; 38 | b = (b + 1) * 4 - 1; 39 | 40 | script! { 41 | {a} OP_PICK {b+1} OP_ROLL 42 | {a+1} OP_PICK {b+2} OP_ROLL 43 | {a+2} OP_PICK {b+3} OP_ROLL 44 | {a+3} OP_PICK {b+4} OP_ROLL 45 | } 46 | } 47 | 48 | pub fn _u32_zip_copy(mut a: u32, mut b: u32) -> Script { 49 | assert!(a < b); 50 | 51 | a = (a + 1) * 4 - 1; 52 | b = (b + 1) * 4 - 1; 53 | script! { 54 | {a} OP_ROLL {b} OP_PICK 55 | {a+1} OP_ROLL {b} OP_PICK 56 | {a+2} OP_ROLL {b} OP_PICK 57 | {a+3} OP_ROLL {b} OP_PICK 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/fflonk/compute_lagrange.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::fp254impl::Fp254Impl; 4 | use crate::bn254::fr::Fr; 5 | use crate::treepp::*; 6 | use ark_ff::Field; 7 | use num_bigint::BigUint; 8 | use std::str::FromStr; 9 | 10 | #[test] 11 | fn test_compute_lagrange() { 12 | let mut li_1_inv = ark_bn254::Fr::from_str( 13 | "2173335263468457880677030391603678787407318523287432531877773790452047235821", 14 | ) 15 | .unwrap(); 16 | li_1_inv.inverse_in_place().unwrap(); 17 | 18 | let mut li_2_inv = ark_bn254::Fr::from_str( 19 | "3695504780263816985137938305786365026932326252410439503136485422302932463173", 20 | ) 21 | .unwrap(); 22 | li_2_inv.inverse_in_place().unwrap(); 23 | 24 | let script = script! { 25 | // push zh 26 | { Fr::push_dec("9539499652122301619680560867461437153480631573357135330838514610439758374055") } 27 | 28 | // push the inverse of Li_1 29 | { Fr::push_u32_le(&BigUint::from(li_1_inv).to_u32_digits()) } 30 | 31 | { Fr::copy(1) } 32 | { Fr::toaltstack() } 33 | 34 | { Fr::mul() } 35 | 36 | // check L[1] 37 | { Fr::push_dec("19264250262515049392118907974032894668050943806280011767302681470321758079402") } 38 | { Fr::equalverify(1, 0) } 39 | 40 | // push the inverse of Li_2 41 | { Fr::push_u32_le(&BigUint::from(li_2_inv).to_u32_digits()) } 42 | { Fr::fromaltstack() } 43 | { Fr::mul() } 44 | { Fr::push_dec("11699596668367776675346610687704220591435078791727316319397053191800576917728") } 45 | { Fr::mul() } 46 | 47 | // check L[2] 48 | { Fr::push_dec("5147149846110622280763906966379810308773882279335494056719681880590330080749") } 49 | { Fr::equalverify(1, 0) } 50 | 51 | OP_TRUE 52 | }; 53 | 54 | println!("fflonk.compute_lagrange = {} bytes", script.len()); 55 | 56 | let exec_result = execute_script(script); 57 | assert!(exec_result.success); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/fflonk/circom_ref/proof.json: -------------------------------------------------------------------------------- 1 | { 2 | "polynomials": { 3 | "C1": [ 4 | "8993820735255461694205287896466659762517378169680151817278189507219986014273", 5 | "20608602847008036615737932995836476570376266531776948091942386633580114403199", 6 | "1" 7 | ], 8 | "C2": [ 9 | "7381325072443970270370678023564870071058744625357849943766655609499175274412", 10 | "15178578915928592705383893120230835636411008017183180871962629962483134367891", 11 | "1" 12 | ], 13 | "W1": [ 14 | "32650538602400348219903702316313439265244325226254563471430382441955222030", 15 | "1102261574488401129043229793384018650738538286437537952751903719159654317199", 16 | "1" 17 | ], 18 | "W2": [ 19 | "11695827642347470645483614914520090101440686332033956264171712726147972703435", 20 | "8930092616903485317239646434389939466400752538134075201209141980838088395614", 21 | "1" 22 | ] 23 | }, 24 | "evaluations": { 25 | "ql": "4305584171954448775801758618991977283131671407134816099015723841718827300684", 26 | "qr": "12383383973686840675128398394454489421896122330596726461131121746926747341189", 27 | "qm": "84696450614978050680673343346456326547032107368333805624994614151289555853", 28 | "qo": "3940439340424631873531863239669720717811550024514867065774687720368464792371", 29 | "qc": "16961785810060156933739931986193776143069216115530808410139185289490606944009", 30 | "s1": "12474437127153975801320290893919924661315458586210754316226946498711086665749", 31 | "s2": "599434615255095347665395089945860172292558760398201299457995057871688253664", 32 | "s3": "16217604511932175446614838218599989473511950977205890369538297955449224727219", 33 | "a": "7211168621666826182043583595845418959530786367587156242724929610231435505336", 34 | "b": "848088075173937026388846472327431819307508078325359401333033359624801042", 35 | "c": "18963734392470978715233675860777231227480937309534365140504133190694875258320", 36 | "z": "2427313569771756255376235777000596702684056445296844486767054635200432142794", 37 | "zw": "8690328511114991742730387856275843464438882369629727414507275814599493141660", 38 | "t1w": "20786626696833495453279531623626288211765949258916047124642669459480728122908", 39 | "t2w": "12092130080251498309415337127155404037148503145602589831662396526189421234148", 40 | "inv": "21247383512588455895834686692756529012394058115069710447132959660051940541361" 41 | }, 42 | "protocol": "fflonk", 43 | "curve": "bn128" 44 | } -------------------------------------------------------------------------------- /src/fflonk/compute_f.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::curves::G1Projective; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fr::Fr; 7 | use crate::treepp::*; 8 | 9 | #[test] 10 | fn test_compute_f() { 11 | let script = script! { 12 | // push (C0x, C0y), C1, C2 (9 elements) 13 | { Fq::push_dec("303039279492065453055049758769758984569666029850327527958551993331680103359") } 14 | { Fq::push_dec("15061669176783843627135305167141360334623983780813847469326507992811672859575") } 15 | { Fq::push_dec("1") } 16 | 17 | { Fq::push_dec("8993820735255461694205287896466659762517378169680151817278189507219986014273") } 18 | { Fq::push_dec("20608602847008036615737932995836476570376266531776948091942386633580114403199") } 19 | { Fq::push_dec("1") } 20 | 21 | { Fq::push_dec("7381325072443970270370678023564870071058744625357849943766655609499175274412") } 22 | { Fq::push_dec("15178578915928592705383893120230835636411008017183180871962629962483134367891") } 23 | { Fq::push_dec("1") } 24 | 25 | // push quotient1, quotient2 (2 elements) 26 | { Fr::push_dec("8336823378405991273186613678056299833572545852849807089784419620701331198620") } 27 | { Fr::push_dec("9383905404220215760494220727835590239846562451983646600728203514340336934716") } 28 | 29 | { Fr::toaltstack() } 30 | { Fr::toaltstack() } 31 | 32 | { G1Projective::roll(1) } // [c0, c2, c1, q1; q2] 33 | { Fr::fromaltstack() } 34 | { Fq::roll(6)} {Fq::roll(6)} {Fq::roll(6)} // [c0, c1, q1, c2] 35 | { Fr::fromaltstack() } // [c0, c1, q1, c2, q2] 36 | { G1Projective::batched_scalar_mul::<2>() } 37 | { G1Projective::add() } 38 | 39 | { Fq::push_dec("10827057179016943379099096512257711381208881258335395636699788359889105647796") } 40 | { Fq::push_dec("15908485457276609870374048914742234656312588226903176268190825086381552148601") } 41 | { Fq::push_dec("10704903381596808863042656941383257630189957941456629442401491652278045385710") } 42 | 43 | { G1Projective::equalverify() } 44 | OP_TRUE 45 | }; 46 | 47 | println!("fflonk.compute_f = {} bytes", script.len()); 48 | 49 | let exec_result = execute_script(script); 50 | assert!(exec_result.success); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/signatures/winternitz_hash.rs: -------------------------------------------------------------------------------- 1 | use crate::treepp::*; 2 | use crate::signatures::winternitz::{sign, checksig_verify}; 3 | use crate::hash::blake3::blake3_160_var_length; 4 | use blake3::hash; 5 | 6 | const MESSAGE_HASH_LEN: u8 = 20; 7 | 8 | 9 | /// Verify a Winternitz signature for the blake3 hash of the top `input_len` many bytes on the stack 10 | /// Fails if the signature is invalid 11 | pub fn check_hash_sig(sec_key: &str, input_len: usize) -> Script { 12 | script! { 13 | // 1. Verify the signature and compute the signed message 14 | { checksig_verify(sec_key) } 15 | for _ in 0..MESSAGE_HASH_LEN { 16 | OP_TOALTSTACK 17 | } 18 | 19 | // 2. Hash the inputs 20 | { blake3_160_var_length(input_len) } 21 | 22 | // 3. Compare signed message to the hash 23 | for _ in 0..MESSAGE_HASH_LEN / 4 { 24 | for j in 0..4 { 25 | { 3 - j } 26 | OP_ROLL 27 | OP_FROMALTSTACK 28 | OP_EQUALVERIFY 29 | } 30 | } 31 | } 32 | } 33 | 34 | /// Create a Winternitz signature for the blake3 hash of a given message 35 | pub fn sign_hash(sec_key: &str, message: &[u8]) -> Script { 36 | let message_hash = hash(message); 37 | let message_hash_bytes = &message_hash.as_bytes()[0..20]; 38 | script! { 39 | { sign(sec_key, message_hash_bytes) } 40 | } 41 | } 42 | 43 | #[cfg(test)] 44 | mod test { 45 | use super::*; 46 | 47 | #[test] 48 | fn test_check_hash_sig() { 49 | 50 | // My secret key 51 | let my_sec_key = "b138982ce17ac813d505b5b40b665d404e9528e7"; 52 | 53 | // The message to sign 54 | let message = *b"This is an arbitrary length input intended for testing purposes...."; 55 | 56 | let script = script! { 57 | // 58 | // Unlocking Script 59 | // 60 | 61 | // 1. Push the message 62 | for byte in message.iter().rev() { 63 | { *byte } 64 | } 65 | // 2. Push the signature 66 | { sign_hash(my_sec_key, &message) } 67 | 68 | 69 | // 70 | // Locking Script 71 | // 72 | { check_hash_sig(my_sec_key, message.len()) } 73 | OP_TRUE 74 | }; 75 | 76 | 77 | let exec_result = execute_script(script); 78 | if !exec_result.success { 79 | println!("ERROR: {:?} <--- \n STACK: {:4} ", exec_result.last_opcode, exec_result.final_stack); 80 | } 81 | assert!(exec_result.success); 82 | } 83 | 84 | 85 | } -------------------------------------------------------------------------------- /src/fflonk/checkpairing_normalize.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::fp254impl::Fp254Impl; 4 | use crate::bn254::fq::Fq; 5 | use crate::bn254::fr::Fr; 6 | use crate::treepp::*; 7 | use ark_ec::{AffineRepr, CurveGroup}; 8 | use ark_ff::Field; 9 | use num_bigint::BigUint; 10 | use std::str::FromStr; 11 | 12 | #[test] 13 | fn test_checkpairing_normalize() { 14 | // note: this is not necessarily the point that the verifier obtains 15 | 16 | let projective = ark_bn254::G1Projective::new( 17 | ark_bn254::Fq::from_str( 18 | "21025932300722401404248737517866966587837387913191004025854702115722286998035", 19 | ) 20 | .unwrap(), 21 | ark_bn254::Fq::from_str( 22 | "5748766770337880144484917096976043621609890780406924686031233755006782215858", 23 | ) 24 | .unwrap(), 25 | ark_bn254::Fq::from_str( 26 | "18747233771850556311508953762939425433543524671221692065979284256379095132287", 27 | ) 28 | .unwrap(), 29 | ); 30 | let affine = projective.into_affine(); 31 | 32 | let mut inv = ark_bn254::Fq::from_str( 33 | "18747233771850556311508953762939425433543524671221692065979284256379095132287", 34 | ) 35 | .unwrap(); 36 | inv.inverse_in_place().unwrap(); 37 | 38 | let script = script! { 39 | { Fq::push_dec("21025932300722401404248737517866966587837387913191004025854702115722286998035") } 40 | { Fq::push_dec("5748766770337880144484917096976043621609890780406924686031233755006782215858") } 41 | { Fq::push_dec("18747233771850556311508953762939425433543524671221692065979284256379095132287") } 42 | 43 | { Fq::inv() } 44 | 45 | { Fq::copy(0) } 46 | { Fq::square() } 47 | { Fq::copy(0) } { Fr::toaltstack() } 48 | 49 | { Fq::roll(3) } 50 | { Fq::mul() } 51 | 52 | { Fq::fromaltstack() } 53 | { Fq::roll(2) } 54 | { Fq::mul() } 55 | { Fq::roll(2) } 56 | { Fq::mul() } 57 | 58 | // y 59 | { Fq::push_u32_le(&BigUint::from(affine.y().unwrap()).to_u32_digits()) } 60 | { Fq::equalverify(1, 0) } 61 | 62 | // x 63 | { Fq::push_u32_le(&BigUint::from(affine.x().unwrap()).to_u32_digits()) } 64 | { Fq::equalverify(1, 0) } 65 | 66 | OP_TRUE 67 | }; 68 | 69 | println!("fflonk.checkpairing_normalize = {} bytes", script.len()); 70 | 71 | let exec_result = execute_script(script); 72 | assert!(exec_result.success); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/fflonk/checkpairing_a1.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::curves::G1Projective; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fr::Fr; 7 | use crate::treepp::*; 8 | 9 | #[test] 10 | fn test_checkpairing_a1() { 11 | let script = script! { 12 | // push F, E, J, W2 13 | { Fq::push_dec("10827057179016943379099096512257711381208881258335395636699788359889105647796") } 14 | { Fq::push_dec("15908485457276609870374048914742234656312588226903176268190825086381552148601") } 15 | { Fq::push_dec("10704903381596808863042656941383257630189957941456629442401491652278045385710") } 16 | 17 | { Fq::push_dec("10905825615646575916826598897124608361270584984190374057529352166783343482862") } 18 | { Fq::push_dec("19290909793509893735943189519527824156597590461000288988451227768509803549366") } 19 | { Fq::push_dec("10334981607594421347972269000738063023881743479366183631046354259553646162574") } 20 | 21 | { Fq::push_dec("2959562071167086018427906252728568621973040394868315776950851582459669551081") } 22 | { Fq::push_dec("5248835691815263544471788309691308785423871173394577194626050104765380585421") } 23 | { Fq::push_dec("19277062899702791882368245424983329716198384271778017207570439921049817477033") } 24 | 25 | { Fq::push_dec("11695827642347470645483614914520090101440686332033956264171712726147972703435") } 26 | { Fq::push_dec("8930092616903485317239646434389939466400752538134075201209141980838088395614") } 27 | { Fq::push_dec("1") } 28 | 29 | // push y 30 | { Fr::push_dec("6824639836122392703554190210911349683223362245243195922653951653214183338070") } 31 | 32 | { G1Projective::scalar_mul() } 33 | { G1Projective::roll(3) } 34 | { G1Projective::add() } 35 | 36 | { G1Projective::roll(2) } 37 | { G1Projective::neg() } 38 | { G1Projective::add() } 39 | 40 | { G1Projective::roll(1) } 41 | { G1Projective::neg() } 42 | { G1Projective::add() } 43 | 44 | { Fq::push_dec("21025932300722401404248737517866966587837387913191004025854702115722286998035") } 45 | { Fq::push_dec("5748766770337880144484917096976043621609890780406924686031233755006782215858") } 46 | { Fq::push_dec("18747233771850556311508953762939425433543524671221692065979284256379095132287") } 47 | 48 | { G1Projective::equalverify() } 49 | OP_TRUE 50 | }; 51 | 52 | println!("fflonk.checkpairing_a = {} bytes", script.len()); 53 | 54 | let exec_result = execute_script(script); 55 | assert!(exec_result.success); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/bigint/mul.rs: -------------------------------------------------------------------------------- 1 | use crate::bigint::BigIntImpl; 2 | use crate::pseudo::push_to_stack; 3 | use crate::treepp::{script, Script}; 4 | 5 | impl BigIntImpl { 6 | pub fn mul() -> Script { 7 | script! { 8 | { Self::convert_to_be_bits_toaltstack() } 9 | 10 | { push_to_stack(0,Self::N_LIMBS as usize) } 11 | 12 | 13 | OP_FROMALTSTACK 14 | OP_IF 15 | { Self::copy(1) } 16 | { Self::add(1, 0) } 17 | OP_ENDIF 18 | 19 | for _ in 1..N_BITS - 1 { 20 | { Self::roll(1) } 21 | { Self::double(0) } 22 | { Self::roll(1) } 23 | OP_FROMALTSTACK 24 | OP_IF 25 | { Self::copy(1) } 26 | { Self::add(1, 0) } 27 | OP_ENDIF 28 | } 29 | 30 | { Self::roll(1) } 31 | { Self::double(0) } 32 | OP_FROMALTSTACK 33 | OP_IF 34 | { Self::add(1, 0) } 35 | OP_ELSE 36 | { Self::drop() } 37 | OP_ENDIF 38 | } 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod test { 44 | use crate::bigint::{U254, U64}; 45 | use crate::treepp::*; 46 | use core::ops::{Mul, Rem, Shl}; 47 | use num_bigint::{BigUint, RandomBits}; 48 | use num_traits::One; 49 | use rand::{Rng, SeedableRng}; 50 | use rand_chacha::ChaCha20Rng; 51 | 52 | #[test] 53 | fn test_mul() { 54 | let mut prng = ChaCha20Rng::seed_from_u64(0); 55 | for _ in 0..3 { 56 | let a: BigUint = prng.sample(RandomBits::new(254)); 57 | let b: BigUint = prng.sample(RandomBits::new(254)); 58 | let c: BigUint = (a.clone().mul(b.clone())).rem(BigUint::one().shl(254)); 59 | 60 | let script = script! { 61 | { U254::push_u32_le(&a.to_u32_digits()) } 62 | { U254::push_u32_le(&b.to_u32_digits()) } 63 | { U254::mul() } 64 | { U254::push_u32_le(&c.to_u32_digits()) } 65 | { U254::equalverify(1, 0) } 66 | OP_TRUE 67 | }; 68 | let exec_result = execute_script(script); 69 | assert!(exec_result.success); 70 | } 71 | 72 | for _ in 0..3 { 73 | let a: BigUint = prng.sample(RandomBits::new(64)); 74 | let b: BigUint = prng.sample(RandomBits::new(64)); 75 | let c: BigUint = (a.clone().mul(b.clone())).rem(BigUint::one().shl(64)); 76 | 77 | let script = script! { 78 | { U64::push_u32_le(&a.to_u32_digits()) } 79 | { U64::push_u32_le(&b.to_u32_digits()) } 80 | { U64::mul() } 81 | { U64::push_u32_le(&c.to_u32_digits()) } 82 | { U64::equalverify(1, 0) } 83 | OP_TRUE 84 | }; 85 | let exec_result = execute_script(script); 86 | assert!(exec_result.success); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/fflonk/checkpairing_zerotest.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::fp254impl::Fp254Impl; 4 | use crate::bn254::fq::Fq; 5 | use crate::bn254::fq12::Fq12; 6 | use crate::treepp::*; 7 | use ark_ec::pairing::Pairing; 8 | use ark_ec::CurveGroup; 9 | use ark_ff::{CyclotomicMultSubgroup, Field}; 10 | use ark_std::UniformRand; 11 | use bitcoin_script::script; 12 | use num_bigint::BigUint; 13 | use rand::SeedableRng; 14 | use rand_chacha::ChaCha20Rng; 15 | use std::ops::{Mul, Neg}; 16 | use std::str::FromStr; 17 | 18 | fn fq12_push(element: ark_bn254::Fq12) -> Script { 19 | script! { 20 | for elem in element.to_base_prime_field_elements() { 21 | { Fq::push_u32_le(&BigUint::from(elem).to_u32_digits()) } 22 | } 23 | } 24 | } 25 | 26 | #[test] 27 | fn test_checkpairing_zerotest() { 28 | let mut prng = ChaCha20Rng::seed_from_u64(0); 29 | 30 | let x = ark_bn254::fr::Fr::rand(&mut prng); 31 | 32 | let a = ark_bn254::g1::G1Affine::rand(&mut prng); 33 | let b = ark_bn254::g2::G2Affine::rand(&mut prng); 34 | 35 | let ax = a.mul(&x).into_affine(); 36 | let bx = b.mul(&x).into_affine(); 37 | 38 | let c = ark_bn254::Bn254::multi_miller_loop_affine([a.neg(), ax], [bx, b]).0; 39 | 40 | let c_cyc = { 41 | let f1 = c.cyclotomic_inverse().unwrap(); 42 | 43 | let mut f2 = c.inverse().unwrap(); 44 | let mut r = f1.mul(&f2); 45 | f2 = r; 46 | 47 | r.frobenius_map_in_place(2); 48 | 49 | r *= f2; 50 | r 51 | }; 52 | 53 | let exp = BigUint::from_str("4436617972506257923193419177489456460765748607520165056184824179968964824433551145989002390683181468014844846405056222620624959232531272028933759852593591675750731194524123260979423353851618673937937363358520803481826312825518387").unwrap(); 54 | let hint = c_cyc.cyclotomic_exp(exp.to_u64_digits()); 55 | 56 | let r = BigUint::from_str( 57 | "21888242871839275222246405745257275088548364400416034343698204186575808495617", 58 | ) 59 | .unwrap(); 60 | let res = hint.cyclotomic_exp(r.to_u64_digits()); 61 | 62 | assert_eq!(res, c_cyc); 63 | 64 | let script = script! { 65 | // push the hint 66 | { fq12_push(hint) } 67 | 68 | // push c 69 | { fq12_push(c) } 70 | 71 | // make c cyclotomic 72 | { Fq12::move_to_cyclotomic() } 73 | 74 | // check that the hint is cyclotomic 75 | { Fq12::roll(12) } 76 | { Fq12::cyclotomic_verify_in_place() } 77 | 78 | // power the hint by r 79 | { Fq12::cyclotomic_pow_by_r() } 80 | 81 | // check equality 82 | { Fq12::equalverify() } 83 | 84 | OP_TRUE 85 | }; 86 | 87 | println!("fflonk.checkpairing_zerotest = {} bytes", script.len()); 88 | 89 | let exec_result = execute_script(script); 90 | assert!(exec_result.success); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/groth16/test.rs: -------------------------------------------------------------------------------- 1 | use crate::execute_script_without_stack_limit; 2 | use crate::groth16::verifier::Verifier; 3 | use ark_bn254::Bn254; 4 | use ark_crypto_primitives::snark::{CircuitSpecificSetupSNARK, SNARK}; 5 | use ark_ec::pairing::Pairing; 6 | use ark_ff::PrimeField; 7 | use ark_groth16::Groth16; 8 | use ark_relations::lc; 9 | use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; 10 | use ark_std::{end_timer, start_timer, test_rng, UniformRand}; 11 | use rand::{RngCore, SeedableRng}; 12 | 13 | #[derive(Copy)] 14 | struct DummyCircuit { 15 | pub a: Option, 16 | pub b: Option, 17 | pub num_variables: usize, 18 | pub num_constraints: usize, 19 | } 20 | 21 | impl Clone for DummyCircuit { 22 | fn clone(&self) -> Self { 23 | DummyCircuit { 24 | a: self.a, 25 | b: self.b, 26 | num_variables: self.num_variables, 27 | num_constraints: self.num_constraints, 28 | } 29 | } 30 | } 31 | 32 | impl ConstraintSynthesizer for DummyCircuit { 33 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 34 | let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; 35 | let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?; 36 | let c = cs.new_input_variable(|| { 37 | let a = self.a.ok_or(SynthesisError::AssignmentMissing)?; 38 | let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; 39 | 40 | Ok(a * b) 41 | })?; 42 | 43 | for _ in 0..(self.num_variables - 3) { 44 | let _ = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; 45 | } 46 | 47 | for _ in 0..self.num_constraints - 1 { 48 | cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; 49 | } 50 | 51 | cs.enforce_constraint(lc!(), lc!(), lc!())?; 52 | 53 | Ok(()) 54 | } 55 | } 56 | 57 | #[test] 58 | fn test_groth16_verifier() { 59 | type E = Bn254; 60 | let k = 6; 61 | let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); 62 | let circuit = DummyCircuit::<::ScalarField> { 63 | a: Some(::ScalarField::rand(&mut rng)), 64 | b: Some(::ScalarField::rand(&mut rng)), 65 | num_variables: 10, 66 | num_constraints: 1 << k, 67 | }; 68 | let (pk, vk) = Groth16::::setup(circuit, &mut rng).unwrap(); 69 | 70 | let c = circuit.a.unwrap() * circuit.b.unwrap(); 71 | 72 | let proof = Groth16::::prove(&pk, circuit, &mut rng).unwrap(); 73 | 74 | let start = start_timer!(|| "collect_script"); 75 | let script = Verifier::verify_proof(&vec![c], &proof, &vk); 76 | end_timer!(start); 77 | 78 | println!("groth16::test_verify_proof = {} bytes", script.len()); 79 | 80 | let start = start_timer!(|| "execute_script"); 81 | let exec_result = execute_script_without_stack_limit(script); 82 | end_timer!(start); 83 | 84 | assert!(exec_result.success); 85 | } 86 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitvm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | exclude = ["tests"] 6 | 7 | [dependencies] 8 | #bitcoin-script = { path = "../rust-bitcoin-script"} 9 | bitcoin-script = { git = "https://github.com/BitVM/rust-bitcoin-script", branch= "chunker" } 10 | bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm", features = ["rand-std"]} 11 | strum = "0.26" 12 | strum_macros = "0.26" 13 | hex = "0.4.3" 14 | bitcoin-scriptexec = { git = "https://github.com/BitVM/rust-bitcoin-scriptexec/"} 15 | serde = { version = "1.0.197", features = ["derive"] } 16 | num-bigint = "0.4.4" 17 | num-traits = "0.2.18" 18 | ark-bn254 = { git = "https://github.com/Antalpha-Labs/algebra/", features = ["curve"], default-features = false } 19 | ark-ff = { git = "https://github.com/Antalpha-Labs/algebra/" } 20 | ark-ec = { git = "https://github.com/Antalpha-Labs/algebra/" } 21 | ark-groth16 = { git = "https://github.com/Antalpha-Labs/groth16" } 22 | sha2 = "0.10.8" 23 | tokio = { version = "1.37.0", features = ["full"] } 24 | esplora-client = { git = "https://github.com/BitVM/rust-esplora-client" } 25 | serde_json = "1.0.116" 26 | lazy_static = "1.4.0" 27 | bitcoin-script-stack = { git = "https://github.com/FairgateLabs/rust-bitcoin-script-stack"} 28 | rand = "0.8.5" 29 | rand_chacha = "0.3.1" 30 | once_cell = "1.19.0" 31 | blake3 = "=1.5.1" 32 | 33 | [dev-dependencies] 34 | num-bigint = { version = "0.4.4", features = ["rand"] } 35 | ark-std = { version = "0.4.0", default-features = false, features = ["print-trace"] } 36 | ark-crypto-primitives = { git = "https://github.com/Antalpha-Labs/crypto-primitives", features = ["snark", "sponge"] } 37 | ark-relations = { git = "https://github.com/Antalpha-Labs/snark/" } 38 | 39 | [profile.dev] 40 | opt-level = 3 41 | 42 | [profile.release] 43 | lto = true 44 | 45 | [patch.crates-io] 46 | base58check = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 47 | bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 48 | bitcoin_hashes = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 49 | bitcoin-internals = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 50 | bitcoin-io = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 51 | bitcoin-units = { git = "https://github.com/rust-bitcoin/rust-bitcoin", branch = "bitvm"} 52 | 53 | ark-ff = { git = "https://github.com/Antalpha-Labs/algebra/" } 54 | ark-ec = { git = "https://github.com/Antalpha-Labs/algebra/" } 55 | ark-poly = { git = "https://github.com/Antalpha-Labs/algebra/" } 56 | ark-serialize = { git = "https://github.com/Antalpha-Labs/algebra/" } 57 | ark-bn254 = { git = "https://github.com/Antalpha-Labs/algebra/", features = ["curve"], default-features = false } 58 | 59 | ark-r1cs-std = { git = "https://github.com/Antalpha-Labs/r1cs-std/" } 60 | ark-crypto-primitives = { git = "https://github.com/Antalpha-Labs/crypto-primitives/" } 61 | 62 | ark-relations = { git = "https://github.com/Antalpha-Labs/snark/" } 63 | ark-snark = { git = "https://github.com/Antalpha-Labs/snark/" } 64 | ark-groth16 = { git = "https://github.com/Antalpha-Labs/groth16" } 65 | -------------------------------------------------------------------------------- /src/u32/u32_add.rs: -------------------------------------------------------------------------------- 1 | use crate::treepp::{script, Script}; 2 | use crate::u32::u32_zip::{u32_copy_zip, u32_zip}; 3 | 4 | pub fn u8_add_carry() -> Script { 5 | script! { 6 | OP_ADD 7 | OP_DUP 8 | 255 9 | OP_GREATERTHAN 10 | OP_IF 11 | 256 12 | OP_SUB 13 | 1 14 | OP_ELSE 15 | 0 16 | OP_ENDIF 17 | } 18 | } 19 | 20 | pub fn u8_add() -> Script { 21 | script! { 22 | OP_ADD 23 | OP_DUP 24 | 255 25 | OP_GREATERTHAN 26 | OP_IF 27 | 256 28 | OP_SUB 29 | OP_ENDIF 30 | } 31 | } 32 | 33 | /// Addition of two u32 values represented as u8 34 | /// Copies the first summand `a` and drops `b` 35 | pub fn u32_add(a: u32, b: u32) -> Script { 36 | assert_ne!(a, b); 37 | script! { 38 | {u32_copy_zip(a, b)} 39 | 40 | // A0 + B0 41 | u8_add_carry 42 | OP_SWAP 43 | OP_TOALTSTACK 44 | 45 | // A1 + B1 + carry_0 46 | OP_ADD 47 | u8_add_carry 48 | OP_SWAP 49 | OP_TOALTSTACK 50 | 51 | // A2 + B2 + carry_1 52 | OP_ADD 53 | u8_add_carry 54 | OP_SWAP 55 | OP_TOALTSTACK 56 | 57 | // A3 + B3 + carry_2 58 | OP_ADD 59 | u8_add 60 | 61 | OP_FROMALTSTACK 62 | OP_FROMALTSTACK 63 | OP_FROMALTSTACK 64 | 65 | // Now there's the result C_3 C_2 C_1 C_0 on the stack 66 | } 67 | } 68 | 69 | /// Addition of two u32 values represented as u8 70 | /// Drops both summands `a` and `b` 71 | pub fn u32_add_drop(a: u32, b: u32) -> Script { 72 | assert_ne!(a, b); 73 | script! { 74 | {u32_zip(a, b)} 75 | 76 | // A0 + B0 77 | u8_add_carry 78 | OP_SWAP 79 | OP_TOALTSTACK 80 | 81 | // A1 + B1 + carry_0 82 | OP_ADD 83 | u8_add_carry 84 | OP_SWAP 85 | OP_TOALTSTACK 86 | 87 | // A2 + B2 + carry_1 88 | OP_ADD 89 | u8_add_carry 90 | OP_SWAP 91 | OP_TOALTSTACK 92 | 93 | // A3 + B3 + carry_2 94 | OP_ADD 95 | u8_add 96 | 97 | OP_FROMALTSTACK 98 | OP_FROMALTSTACK 99 | OP_FROMALTSTACK 100 | 101 | // Now there's the result C_3 C_2 C_1 C_0 on the stack 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod test { 107 | use crate::treepp::{execute_script, script}; 108 | use crate::u32::u32_add::*; 109 | use crate::u32::u32_std::u32_push; 110 | 111 | #[test] 112 | fn test_u32_add() { 113 | let u32_value_a = 0xFFEEFFEEu32; 114 | let u32_value_b = 0xEEFFEEFFu32; 115 | 116 | let script = script! { 117 | { u32_push(u32_value_a) } 118 | { u32_push(u32_value_b) } 119 | { u32_add_drop(1, 0) } 120 | 0xed OP_EQUALVERIFY 121 | 0xee OP_EQUALVERIFY 122 | 0xee OP_EQUALVERIFY 123 | 0xee OP_EQUAL 124 | }; 125 | let exec_result = execute_script(script); 126 | assert!(exec_result.success) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/bn254/msm.rs: -------------------------------------------------------------------------------- 1 | use crate::bn254::curves::G1Projective; 2 | use crate::bn254::fp254impl::Fp254Impl; 3 | use crate::bn254::fq::Fq; 4 | use crate::bn254::fr::Fr; 5 | use crate::treepp::{script, Script}; 6 | use ark_ff::Field; 7 | use num_bigint::BigUint; 8 | 9 | fn g1_projective_push(point: ark_bn254::G1Projective) -> Script { 10 | script! { 11 | { Fq::push_u32_le(&BigUint::from(point.x).to_u32_digits()) } 12 | { Fq::push_u32_le(&BigUint::from(point.y).to_u32_digits()) } 13 | { Fq::push_u32_le(&BigUint::from(point.z).to_u32_digits()) } 14 | } 15 | } 16 | 17 | pub fn g1_affine_push(point: ark_bn254::G1Affine) -> Script { 18 | script! { 19 | { Fq::push_u32_le(&BigUint::from(point.x).to_u32_digits()) } 20 | { Fq::push_u32_le(&BigUint::from(point.y).to_u32_digits()) } 21 | } 22 | } 23 | 24 | fn fr_push(scalar: ark_bn254::Fr) -> Script { 25 | script! { 26 | { Fr::push_u32_le(&BigUint::from(scalar).to_u32_digits()) } 27 | } 28 | } 29 | 30 | // Will compute msm and return the affine point 31 | // Output Stack: [x,y] 32 | pub fn msm(bases: &[ark_bn254::G1Affine], scalars: &[ark_bn254::Fr]) -> Script { 33 | assert_eq!(bases.len(), scalars.len()); 34 | let bases: Vec> = 35 | bases.iter().map(|&p| p.into()).collect(); 36 | let len = bases.len(); 37 | let scalar_mul = G1Projective::scalar_mul(); 38 | 39 | script! { 40 | // 1. init the sum=0; 41 | {G1Projective::push_zero()} 42 | for i in 0..len { 43 | // 2. scalar mul 44 | { g1_projective_push(bases[i]) } 45 | if scalars[i] > ark_bn254::Fr::ONE { 46 | { fr_push(scalars[i]) } 47 | { scalar_mul.clone() } 48 | } 49 | 50 | // 3. sum the base 51 | { G1Projective::add() } 52 | } 53 | // convert into Affine 54 | { G1Projective::into_affine() } 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod test { 60 | use super::*; 61 | use crate::bn254::curves::G1Affine; 62 | use crate::execute_script; 63 | use ark_ec::{CurveGroup, VariableBaseMSM}; 64 | 65 | use ark_std::{end_timer, start_timer, test_rng, UniformRand}; 66 | 67 | #[test] 68 | fn test_msm_script() { 69 | let k = 2; 70 | let n = 1 << k; 71 | let rng = &mut test_rng(); 72 | 73 | let scalars = (0..n).map(|_| ark_bn254::Fr::rand(rng)).collect::>(); 74 | 75 | let bases = (0..n) 76 | .map(|_| ark_bn254::G1Projective::rand(rng).into_affine()) 77 | .collect::>(); 78 | 79 | let expect = ark_bn254::G1Projective::msm(&bases, &scalars).unwrap(); 80 | let expect = expect.into_affine(); 81 | 82 | let start = start_timer!(|| "collect_script"); 83 | let script = script! { 84 | {super::msm(&bases, &scalars) } 85 | { g1_affine_push(expect) } 86 | { G1Affine::equalverify() } 87 | OP_TRUE 88 | }; 89 | end_timer!(start); 90 | 91 | println!("msm::test_msm_script = {} bytes", script.len()); 92 | let start = start_timer!(|| "execute_msm_script"); 93 | let exec_result = execute_script(script); 94 | end_timer!(start); 95 | assert!(exec_result.success); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/bridge/graph.rs: -------------------------------------------------------------------------------- 1 | use bitcoin::{ 2 | OutPoint, XOnlyPublicKey, 3 | }; 4 | use lazy_static::lazy_static; 5 | use std::{collections::HashMap, str::FromStr}; 6 | 7 | use super::transactions::{BridgeContext, BridgeTransaction}; 8 | 9 | pub const INITIAL_AMOUNT: u64 = 100_000; 10 | pub const FEE_AMOUNT: u64 = 1_000; 11 | pub const DUST_AMOUNT: u64 = 10_000; 12 | 13 | lazy_static! { 14 | static ref UNSPENDABLE_PUBKEY: XOnlyPublicKey = XOnlyPublicKey::from_str( 15 | "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0" 16 | ) 17 | .unwrap(); 18 | } 19 | 20 | // DEMO SECRETS 21 | pub const OPERATOR_SECRET: &str = 22 | "d898098e09898a0980989b980809809809f09809884324874302975287524398"; 23 | pub const N_OF_N_SECRET: &str = "a9bd8b8ade888ed12301b21318a3a73429232343587049870132987481723497"; 24 | 25 | pub type CompiledBitVMGraph = HashMap>>; 26 | 27 | pub fn compile_graph(context: &BridgeContext, initial_outpoint: OutPoint) -> CompiledBitVMGraph { 28 | 29 | // Currently only Assert -> Disprove 30 | 31 | //let mut disprove_txs = vec![]; 32 | //for i in 0..1000 { 33 | // let disprove_tx = Box::new(DisproveTransaction::new( 34 | // context, 35 | // initial_outpoint, 36 | // Amount::from_sat(INITIAL_AMOUNT), 37 | // i, 38 | // )); 39 | // disprove_txs.push(disprove_tx as Box); 40 | //} 41 | //graph.insert(initial_outpoint, disprove_txs); 42 | 43 | // Pre-sign transactions in the graph. 44 | //for transaction_vec in graph.values_mut() { 45 | // for bridge_transaction in transaction_vec.iter_mut() { 46 | // bridge_transaction.pre_sign(context); 47 | // } 48 | //} 49 | HashMap::new() 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | 55 | use crate::bridge::{client::BitVMClient, transactions::connector_c_address}; 56 | 57 | use super::*; 58 | use bitcoin::{Amount, secp256k1::{Secp256k1, Keypair}}; 59 | 60 | #[tokio::test] 61 | async fn test_graph_compile_with_client() { 62 | let secp = Secp256k1::new(); 63 | let n_of_n_key = Keypair::from_seckey_str(&secp, N_OF_N_SECRET).unwrap(); 64 | let operator_key = Keypair::from_seckey_str(&secp, OPERATOR_SECRET).unwrap(); 65 | let mut context = BridgeContext::new(); 66 | context.set_operator_key(operator_key); 67 | context.set_n_of_n_pubkey(n_of_n_key.x_only_public_key().0); 68 | 69 | let mut client = BitVMClient::new(); 70 | let funding_utxo = client 71 | .get_initial_utxo( 72 | connector_c_address(n_of_n_key.x_only_public_key().0), 73 | Amount::from_sat(INITIAL_AMOUNT), 74 | ) 75 | .await 76 | .unwrap_or_else(|| { 77 | panic!( 78 | "Fund {:?} with {} sats at https://faucet.mutinynet.com/", 79 | connector_c_address(n_of_n_key.x_only_public_key().0), 80 | INITIAL_AMOUNT 81 | ); 82 | }); 83 | let funding_outpoint = OutPoint { 84 | txid: funding_utxo.txid, 85 | vout: funding_utxo.vout, 86 | }; 87 | let mut graph = compile_graph(&context, funding_outpoint); 88 | client 89 | .listen(&mut context, funding_outpoint, &mut graph) 90 | .await; 91 | assert!(true); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/u32/u32_and.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::treepp::{script, Script}; 4 | use crate::u32::u32_zip::u32_copy_zip; 5 | 6 | /// The bitwise AND of two u8 elements. 7 | /// Expects the u8_xor_table to be on the stack 8 | pub fn u8_and(i: u32) -> Script { 9 | script! { 10 | // f_A = f(A) 11 | OP_DUP 12 | {i} 13 | OP_ADD 14 | OP_PICK 15 | 16 | // A_even = f_A << 1 17 | OP_DUP 18 | OP_DUP 19 | OP_ADD 20 | 21 | // A_odd = A - A_even 22 | OP_ROT 23 | OP_SWAP 24 | OP_SUB 25 | 26 | // f_B = f(B) 27 | OP_ROT 28 | OP_DUP 29 | {i + 1} 30 | OP_ADD 31 | OP_PICK 32 | 33 | // B_even = f_B << 1 34 | OP_DUP 35 | OP_DUP 36 | OP_ADD 37 | 38 | // B_odd = B - B_even 39 | OP_ROT 40 | OP_SWAP 41 | OP_SUB 42 | 43 | // A_andxor_B_even = f_A + f_B 44 | OP_SWAP 45 | 3 46 | OP_ROLL 47 | OP_ADD 48 | // A_and_B_even = f(A_andxor_B_even) 49 | {i} 50 | OP_ADD 51 | OP_PICK 52 | 53 | // A_andxor_B_odd = A_odd + B_odd 54 | OP_SWAP 55 | OP_ROT 56 | OP_ADD 57 | 58 | // A_and_B_odd = f(A_andxor_B_odd) 59 | {i - 1} 60 | OP_ADD 61 | OP_PICK 62 | 63 | // A_and_B = A_and_B_odd + (A_and_B_even << 1) 64 | OP_OVER 65 | OP_ADD 66 | OP_ADD 67 | } 68 | } 69 | 70 | /// The bitwise AND of the u32 elements at address a and at address b. Drops a and b 71 | /// 72 | /// Expects the u8_xor_table to be on the stack 73 | pub fn u32_and(a: u32, b: u32, stack_size: u32) -> Script { 74 | assert_ne!(a, b); 75 | script! { 76 | {u32_copy_zip(a, b)} 77 | 78 | {u8_and(8 + (stack_size - 2) * 4)} 79 | 80 | OP_TOALTSTACK 81 | 82 | {u8_and(6 + (stack_size - 2) * 4)} 83 | 84 | OP_TOALTSTACK 85 | 86 | {u8_and(4 + (stack_size - 2) * 4)} 87 | 88 | OP_TOALTSTACK 89 | 90 | {u8_and(2 + (stack_size - 2) * 4)} 91 | 92 | OP_FROMALTSTACK 93 | OP_FROMALTSTACK 94 | OP_FROMALTSTACK 95 | } 96 | } 97 | 98 | #[cfg(test)] 99 | mod tests { 100 | 101 | use crate::treepp::{execute_script, script}; 102 | use crate::u32::u32_and::*; 103 | use crate::u32::u32_std::*; 104 | use crate::u32::u32_xor::{u8_drop_xor_table, u8_push_xor_table}; 105 | use rand::Rng; 106 | 107 | fn and(x: u32, y: u32) -> u32 { x & y } 108 | 109 | #[test] 110 | fn test_and() { 111 | println!("u32 and: {} bytes", u32_and(0, 1, 3).len()); 112 | for _ in 0..100 { 113 | let mut rng = rand::thread_rng(); 114 | let x: u32 = rng.gen(); 115 | let y: u32 = rng.gen(); 116 | let exec_script = script! { 117 | {u8_push_xor_table()} 118 | {u32_push(x)} 119 | {u32_push(y)} 120 | {u32_and(0, 1, 3)} 121 | {u32_push(and(x, y))} 122 | {u32_equal()} 123 | OP_TOALTSTACK 124 | {u32_drop()} // drop y 125 | {u8_drop_xor_table()} 126 | OP_FROMALTSTACK 127 | }; 128 | let res = execute_script(exec_script); 129 | assert!(res.success); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/u32/u32_or.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::treepp::{script, Script}; 4 | use crate::u32::u32_zip::u32_copy_zip; 5 | 6 | /// Bitwise OR of two u8 elements. 7 | /// Expects the u8_xor_table to be on the stack. 8 | /// 9 | pub fn u8_or(i: u32) -> Script { 10 | script! { 11 | // f_A = f(A) 12 | OP_DUP 13 | {i} 14 | OP_ADD 15 | OP_PICK 16 | 17 | // A_even = f_A << 1 18 | OP_DUP 19 | OP_DUP 20 | OP_ADD 21 | 22 | // A_odd = A - A_even 23 | OP_ROT 24 | OP_SWAP 25 | OP_SUB 26 | 27 | // f_B = f(B) 28 | OP_ROT 29 | OP_DUP 30 | {i + 1} 31 | OP_ADD 32 | OP_PICK 33 | 34 | // B_even = f_B << 1 35 | OP_DUP 36 | OP_DUP 37 | OP_ADD 38 | 39 | // B_odd = B - B_even 40 | OP_ROT 41 | OP_SWAP 42 | OP_SUB 43 | 44 | // A_andxor_B_even = f_A + f_B 45 | OP_SWAP 46 | 3 47 | OP_ROLL 48 | OP_ADD 49 | 50 | // A_and_B_even = f(A_andxor_B_even) 51 | OP_DUP 52 | {i + 1} 53 | OP_ADD 54 | OP_PICK 55 | OP_SUB 56 | 57 | // A_andxor_B_odd = A_odd + B_odd 58 | OP_SWAP 59 | OP_ROT 60 | OP_ADD 61 | 62 | // A_and_B_odd = f(A_andxor_B_odd) 63 | OP_DUP 64 | {i} 65 | OP_ADD 66 | OP_PICK 67 | OP_SUB 68 | 69 | // A_and_B = A_and_B_odd + (A_and_B_even << 1) 70 | OP_OVER 71 | OP_ADD 72 | OP_ADD 73 | } 74 | } 75 | 76 | /// Bitwise OR of two u32 elements. 77 | /// Expects the u8_xor_table to be on the stack 78 | pub fn u32_or(a: u32, b: u32, stack_size: u32) -> Script { 79 | assert_ne!(a, b); 80 | 81 | script! { 82 | {u32_copy_zip(a, b)} 83 | 84 | {u8_or(8 + (stack_size - 2) * 4)} 85 | 86 | OP_TOALTSTACK 87 | 88 | {u8_or(6 + (stack_size - 2) * 4)} 89 | 90 | OP_TOALTSTACK 91 | 92 | {u8_or(4 + (stack_size - 2) * 4)} 93 | 94 | OP_TOALTSTACK 95 | 96 | {u8_or(2 + (stack_size - 2) * 4)} 97 | 98 | 99 | OP_FROMALTSTACK 100 | OP_FROMALTSTACK 101 | OP_FROMALTSTACK 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod tests { 107 | 108 | use crate::treepp::{execute_script, script}; 109 | use crate::u32::u32_or::*; 110 | use crate::u32::u32_std::*; 111 | use crate::u32::u32_xor::{u8_drop_xor_table, u8_push_xor_table}; 112 | use rand::Rng; 113 | 114 | fn or(x: u32, y: u32) -> u32 { x | y } 115 | 116 | #[test] 117 | fn test_or() { 118 | println!("u32 or: {} bytes", u32_or(0, 1, 3).len()); 119 | for _ in 0..100 { 120 | let mut rng = rand::thread_rng(); 121 | let x: u32 = rng.gen(); 122 | let y: u32 = rng.gen(); 123 | let exec_script = script! { 124 | {u8_push_xor_table()} 125 | {u32_push(x)} 126 | {u32_push(y)} 127 | {u32_or(0, 1, 3)} 128 | {u32_push(or(x, y))} 129 | {u32_equal()} 130 | OP_TOALTSTACK 131 | {u32_drop()} // drop y 132 | {u8_drop_xor_table()} 133 | OP_FROMALTSTACK 134 | }; 135 | let res = execute_script(exec_script); 136 | assert!(res.success); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/pseudo.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(dead_code)] 3 | 4 | use crate::treepp::{script, Script}; 5 | 6 | pub fn OP_CHECKSEQUENCEVERIFY() -> Script { 7 | script! {OP_CSV} 8 | } 9 | 10 | /// OP_4PICK 11 | /// The 4 items n back in the stack are copied to the top. 12 | pub fn OP_4PICK() -> Script { 13 | script! { 14 | OP_ADD 15 | OP_DUP OP_PICK OP_SWAP 16 | OP_DUP OP_PICK OP_SWAP 17 | OP_DUP OP_PICK OP_SWAP 18 | OP_1SUB OP_PICK 19 | } 20 | } 21 | 22 | /// OP_4ROLL 23 | /// The 4 items n back in the stack are moved to the top. 24 | pub fn OP_4ROLL() -> Script { 25 | script! { 26 | 4 OP_ADD 27 | OP_DUP OP_ROLL OP_SWAP 28 | OP_DUP OP_ROLL OP_SWAP 29 | OP_DUP OP_ROLL OP_SWAP 30 | OP_1SUB OP_ROLL 31 | } 32 | } 33 | 34 | /// Duplicates the top 4 items 35 | pub fn OP_4DUP() -> Script { 36 | script! { 37 | OP_2OVER OP_2OVER 38 | } 39 | } 40 | 41 | /// Drops the top 4 items 42 | pub fn OP_4DROP() -> Script { 43 | script! { 44 | OP_2DROP OP_2DROP 45 | } 46 | } 47 | 48 | /// Swaps the top two groups of 4 items 49 | pub fn OP_4SWAP() -> Script { 50 | script! { 51 | 7 OP_ROLL 7 OP_ROLL 52 | 7 OP_ROLL 7 OP_ROLL 53 | } 54 | } 55 | 56 | /// Puts the top 4 items onto the top of the alt stack. Removes them from the main stack. 57 | pub fn OP_4TOALTSTACK() -> Script { 58 | script! { 59 | OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK OP_TOALTSTACK 60 | } 61 | } 62 | 63 | /// Puts the top 4 items from the altstack onto the top of the main stack. Removes them from the alt stack. 64 | pub fn OP_4FROMALTSTACK() -> Script { 65 | script! { 66 | OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK 67 | } 68 | } 69 | 70 | // 71 | // Multiplication by Powers of 2 72 | // 73 | 74 | /// The top stack item is multiplied by 2 75 | pub fn OP_2MUL() -> Script { 76 | script! { 77 | OP_DUP OP_ADD 78 | } 79 | } 80 | 81 | /// The top stack item is multiplied by 4 82 | pub fn OP_4MUL() -> Script { 83 | script! { 84 | OP_DUP OP_ADD OP_DUP OP_ADD 85 | } 86 | } 87 | 88 | /// The top stack item is multiplied by 2**k 89 | pub fn op_2k_mul(k: u32) -> Script { 90 | script! { 91 | for _ in 0..k{ 92 | {OP_2MUL()} 93 | } 94 | } 95 | } 96 | 97 | /// The top stack item is multiplied by 16 98 | pub fn OP_16MUL() -> Script { 99 | script! { 100 | OP_DUP OP_ADD OP_DUP OP_ADD 101 | OP_DUP OP_ADD OP_DUP OP_ADD 102 | } 103 | } 104 | 105 | /// The top stack item is multiplied by 256 106 | pub fn OP_256MUL() -> Script { 107 | script! { 108 | OP_DUP OP_ADD OP_DUP OP_ADD 109 | OP_DUP OP_ADD OP_DUP OP_ADD 110 | OP_DUP OP_ADD OP_DUP OP_ADD 111 | OP_DUP OP_ADD OP_DUP OP_ADD 112 | } 113 | } 114 | 115 | pub fn OP_NDUP(n: usize) -> Script { 116 | let times_3_dup = if n > 3 { (n - 3) / 3 } else { 0 }; 117 | let remaining = if n > 3 { (n - 3) % 3 } else { 0 }; 118 | 119 | script! { 120 | 121 | if n >= 1 { 122 | OP_DUP 123 | } 124 | 125 | 126 | if n >= 3 { 127 | OP_2DUP 128 | } 129 | else if n >= 2{ 130 | OP_DUP 131 | } 132 | 133 | 134 | for _ in 0..times_3_dup { 135 | OP_3DUP 136 | } 137 | 138 | if remaining == 2{ 139 | OP_2DUP 140 | } 141 | else if remaining == 1{ 142 | OP_DUP 143 | } 144 | 145 | } 146 | } 147 | 148 | pub fn push_to_stack(element: usize, n: usize) -> Script { 149 | script! { 150 | if n >= 1{ 151 | {element} {OP_NDUP(n - 1)} 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/u4/u4_rot_stack.rs: -------------------------------------------------------------------------------- 1 | //use crate::treepp::{script, Script}; 2 | //use sha2::digest::typenum::bit; 3 | 4 | use bitcoin_script_stack::stack::{StackTracker, StackVariable}; 5 | 6 | use super::u4_shift_stack::{u4_2_nib_shift_stack, u4_rshift_stack}; 7 | 8 | pub fn u4_rrot_nib_from_u32( 9 | stack: &mut StackTracker, 10 | tables: StackVariable, 11 | number: StackVariable, 12 | nib: u32, 13 | shift: u32, 14 | is_shift: bool, 15 | ) -> StackVariable { 16 | let pos_shift = shift / 4; 17 | 18 | if pos_shift > nib && is_shift { 19 | return stack.number(0); 20 | } 21 | 22 | let y = (8 - pos_shift + nib - 1) % 8; 23 | let x = (8 - pos_shift + nib) % 8; 24 | 25 | stack.copy_var_sub_n(number, x); 26 | 27 | let bit_shift = shift % 4; 28 | 29 | if y == 7 && is_shift { 30 | u4_rshift_stack(stack, tables, bit_shift) 31 | } else { 32 | stack.copy_var_sub_n(number, y); 33 | u4_2_nib_shift_stack(stack, tables, bit_shift) 34 | } 35 | } 36 | 37 | pub fn u4_rrot_u32( 38 | stack: &mut StackTracker, 39 | tables: StackVariable, 40 | number: StackVariable, 41 | shift: u32, 42 | is_shift: bool, 43 | ) -> StackVariable { 44 | let vars: Vec = (0..8) 45 | .map(|nib| u4_rrot_nib_from_u32(stack, tables, number, nib, shift, is_shift)) 46 | .collect(); 47 | let mut nib0 = vars[0]; 48 | stack.join_count(&mut nib0, 7); 49 | nib0 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | 55 | use super::*; 56 | use crate::treepp::script; 57 | use crate::u4::u4_shift_stack::u4_push_shift_tables_stack; 58 | use bitcoin_script_stack::stack::StackTracker; 59 | use rand::Rng; 60 | 61 | fn rrot(x: u32, n: u32) -> u32 { 62 | if n == 0 { 63 | return x; 64 | } 65 | (x >> n) | (x << (32 - n)) 66 | } 67 | 68 | fn rshift(x: u32, n: u32) -> u32 { 69 | if n == 0 { 70 | return x; 71 | } 72 | x >> n 73 | } 74 | 75 | #[test] 76 | fn test_rshift_rand() { 77 | let mut rng = rand::thread_rng(); 78 | for _ in 0..100 { 79 | let x: u32 = rng.gen(); 80 | let mut n: u32 = rng.gen(); 81 | n %= 32; 82 | if n % 4 == 0 { 83 | n += 1; 84 | } 85 | 86 | let mut stack = StackTracker::new(); 87 | let tables = u4_push_shift_tables_stack(&mut stack); 88 | let pos = stack.number_u32(x); 89 | u4_rrot_u32(&mut stack, tables, pos, n, true); 90 | 91 | stack.number_u32(rshift(x, n)); 92 | 93 | stack.custom( 94 | script! { 95 | for i in 0..8 { 96 | { 8 - i} 97 | OP_ROLL 98 | OP_EQUALVERIFY 99 | } 100 | }, 101 | 2, 102 | false, 103 | 0, 104 | "verify", 105 | ); 106 | 107 | stack.drop(pos); 108 | stack.drop(tables); 109 | stack.op_true(); 110 | 111 | assert!(stack.run().success); 112 | } 113 | } 114 | 115 | #[test] 116 | fn test_rrot_rand() { 117 | let mut rng = rand::thread_rng(); 118 | for _ in 0..100 { 119 | let x: u32 = rng.gen(); 120 | let mut n: u32 = rng.gen(); 121 | n %= 32; 122 | if n % 4 == 0 { 123 | n += 1; 124 | } 125 | 126 | let mut stack = StackTracker::new(); 127 | let tables = u4_push_shift_tables_stack(&mut stack); 128 | let pos = stack.number_u32(x); 129 | u4_rrot_u32(&mut stack, tables, pos, n, false); 130 | 131 | stack.number_u32(rrot(x, n)); 132 | 133 | stack.custom( 134 | script! { 135 | for i in 0..8 { 136 | { 8 - i} 137 | OP_ROLL 138 | OP_EQUALVERIFY 139 | } 140 | }, 141 | 2, 142 | false, 143 | 0, 144 | "verify", 145 | ); 146 | 147 | stack.drop(pos); 148 | stack.drop(tables); 149 | stack.op_true(); 150 | 151 | assert!(stack.run().success); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/bigint/sub.rs: -------------------------------------------------------------------------------- 1 | use crate::bigint::BigIntImpl; 2 | use crate::treepp::*; 3 | 4 | impl BigIntImpl { 5 | /// Compute the difference of two BigInts 6 | pub fn sub(a: u32, b: u32) -> Script { 7 | script! { 8 | {Self::zip(a, b)} 9 | 10 | { 1 << LIMB_SIZE } 11 | 12 | // A0 - B0 13 | limb_sub_borrow OP_TOALTSTACK 14 | 15 | // from A1 - (B1 + borrow_0) 16 | // to A{N-2} - (B{N-2} + borrow_{N-3}) 17 | for _ in 0..Self::N_LIMBS - 2 { 18 | OP_ROT 19 | OP_ADD 20 | OP_SWAP 21 | limb_sub_borrow OP_TOALTSTACK 22 | } 23 | 24 | // A{N-1} - (B{N-1} + borrow_{N-2}) 25 | OP_NIP 26 | OP_ADD 27 | { limb_sub_noborrow(Self::HEAD_OFFSET) } 28 | 29 | for _ in 0..Self::N_LIMBS - 1 { 30 | OP_FROMALTSTACK 31 | } 32 | } 33 | } 34 | } 35 | 36 | /// Compute the difference of two limbs, including the carry bit 37 | /// 38 | /// Author: @stillsaiko 39 | pub fn limb_sub_borrow() -> Script { 40 | script! { 41 | OP_ROT OP_ROT 42 | OP_SUB 43 | OP_DUP 44 | 0 45 | OP_LESSTHAN 46 | OP_TUCK 47 | OP_IF 48 | 2 OP_PICK OP_ADD 49 | OP_ENDIF 50 | } 51 | } 52 | 53 | /// Compute the sum of two limbs, dropping the carry bit 54 | /// 55 | /// Author: @weikengchen 56 | pub fn limb_sub_noborrow(head_offset: u32) -> Script { 57 | script! { 58 | OP_SUB 59 | OP_DUP 60 | 0 61 | OP_LESSTHAN 62 | OP_IF 63 | { head_offset } 64 | OP_ADD 65 | OP_ENDIF 66 | } 67 | } 68 | 69 | #[cfg(test)] 70 | mod test { 71 | use crate::bigint::{U254, U64}; 72 | use crate::treepp::*; 73 | use core::ops::{Rem, Shl}; 74 | use num_bigint::{BigUint, RandomBits}; 75 | use num_traits::One; 76 | use rand::{Rng, SeedableRng}; 77 | use rand_chacha::ChaCha20Rng; 78 | 79 | #[test] 80 | fn test_sub() { 81 | let mut prng = ChaCha20Rng::seed_from_u64(0); 82 | 83 | for _ in 0..100 { 84 | let a: BigUint = prng.sample(RandomBits::new(254)); 85 | let b: BigUint = prng.sample(RandomBits::new(254)); 86 | let mut c: BigUint = BigUint::one().shl(254) + &a - &b; 87 | c = c.rem(BigUint::one().shl(254)); 88 | 89 | let script = script! { 90 | { U254::push_u32_le(&a.to_u32_digits()) } 91 | { U254::push_u32_le(&b.to_u32_digits()) } 92 | { U254::sub(1, 0) } 93 | { U254::push_u32_le(&c.to_u32_digits()) } 94 | { U254::equalverify(1, 0) } 95 | OP_TRUE 96 | }; 97 | let exec_result = execute_script(script); 98 | assert!(exec_result.success); 99 | 100 | let script = script! { 101 | { U254::push_u32_le(&b.to_u32_digits()) } 102 | { U254::push_u32_le(&a.to_u32_digits()) } 103 | { U254::sub(0, 1) } 104 | { U254::push_u32_le(&c.to_u32_digits()) } 105 | { U254::equalverify(1, 0) } 106 | OP_TRUE 107 | }; 108 | let exec_result = execute_script(script); 109 | assert!(exec_result.success); 110 | } 111 | 112 | for _ in 0..100 { 113 | let a: BigUint = prng.sample(RandomBits::new(64)); 114 | let b: BigUint = prng.sample(RandomBits::new(64)); 115 | let mut c: BigUint = BigUint::one().shl(64) + &a - &b; 116 | c = c.rem(BigUint::one().shl(64)); 117 | 118 | let script = script! { 119 | { U64::push_u32_le(&a.to_u32_digits()) } 120 | { U64::push_u32_le(&b.to_u32_digits()) } 121 | { U64::sub(1, 0) } 122 | { U64::push_u32_le(&c.to_u32_digits()) } 123 | { U64::equalverify(1, 0) } 124 | OP_TRUE 125 | }; 126 | let exec_result = execute_script(script); 127 | assert!(exec_result.success); 128 | 129 | let script = script! { 130 | { U64::push_u32_le(&b.to_u32_digits()) } 131 | { U64::push_u32_le(&a.to_u32_digits()) } 132 | { U64::sub(0, 1) } 133 | { U64::push_u32_le(&c.to_u32_digits()) } 134 | { U64::equalverify(1, 0) } 135 | OP_TRUE 136 | }; 137 | let exec_result = execute_script(script); 138 | assert!(exec_result.success); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/fflonk/check_format.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::curves::G1Affine; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fr::Fr; 7 | use crate::treepp::*; 8 | 9 | 10 | 11 | #[test] 12 | fn test_check_format() { 13 | let script = script! { 14 | // C1 15 | { Fq::push_dec("8993820735255461694205287896466659762517378169680151817278189507219986014273") } 16 | { Fq::push_dec("20608602847008036615737932995836476570376266531776948091942386633580114403199") } 17 | { G1Affine::is_on_curve() } 18 | OP_VERIFY 19 | // C2 20 | { Fq::push_dec("7381325072443970270370678023564870071058744625357849943766655609499175274412") } 21 | { Fq::push_dec("15178578915928592705383893120230835636411008017183180871962629962483134367891") } 22 | { G1Affine::is_on_curve() } 23 | OP_VERIFY 24 | // W1 25 | { Fq::push_dec("32650538602400348219903702316313439265244325226254563471430382441955222030") } 26 | { Fq::push_dec("1102261574488401129043229793384018650738538286437537952751903719159654317199") } 27 | { G1Affine::is_on_curve() } 28 | OP_VERIFY 29 | // W2 30 | { Fq::push_dec("11695827642347470645483614914520090101440686332033956264171712726147972703435") } 31 | { Fq::push_dec("8930092616903485317239646434389939466400752538134075201209141980838088395614") } 32 | { G1Affine::is_on_curve() } 33 | OP_VERIFY 34 | // ql 35 | { Fr::push_dec("4305584171954448775801758618991977283131671407134816099015723841718827300684") } 36 | { Fr::is_field() } 37 | OP_VERIFY 38 | // qr 39 | { Fr::push_dec("12383383973686840675128398394454489421896122330596726461131121746926747341189") } 40 | { Fr::is_field() } 41 | OP_VERIFY 42 | // qm 43 | { Fr::push_dec("84696450614978050680673343346456326547032107368333805624994614151289555853") } 44 | { Fr::is_field() } 45 | OP_VERIFY 46 | // qo 47 | { Fr::push_dec("3940439340424631873531863239669720717811550024514867065774687720368464792371") } 48 | { Fr::is_field() } 49 | OP_VERIFY 50 | // qc 51 | { Fr::push_dec("16961785810060156933739931986193776143069216115530808410139185289490606944009") } 52 | { Fr::is_field() } 53 | OP_VERIFY 54 | // s1 55 | { Fr::push_dec("12474437127153975801320290893919924661315458586210754316226946498711086665749") } 56 | { Fr::is_field() } 57 | OP_VERIFY 58 | // s2 59 | { Fr::push_dec("599434615255095347665395089945860172292558760398201299457995057871688253664") } 60 | { Fr::is_field() } 61 | OP_VERIFY 62 | // s3 63 | { Fr::push_dec("16217604511932175446614838218599989473511950977205890369538297955449224727219") } 64 | { Fr::is_field() } 65 | OP_VERIFY 66 | // a 67 | { Fr::push_dec("7211168621666826182043583595845418959530786367587156242724929610231435505336") } 68 | { Fr::is_field() } 69 | OP_VERIFY 70 | // b 71 | { Fr::push_dec("848088075173937026388846472327431819307508078325359401333033359624801042") } 72 | { Fr::is_field() } 73 | OP_VERIFY 74 | // c 75 | { Fr::push_dec("18963734392470978715233675860777231227480937309534365140504133190694875258320") } 76 | { Fr::is_field() } 77 | OP_VERIFY 78 | // z 79 | { Fr::push_dec("2427313569771756255376235777000596702684056445296844486767054635200432142794") } 80 | { Fr::is_field() } 81 | OP_VERIFY 82 | // zw 83 | { Fr::push_dec("8690328511114991742730387856275843464438882369629727414507275814599493141660") } 84 | { Fr::is_field() } 85 | OP_VERIFY 86 | // t1w 87 | { Fr::push_dec("20786626696833495453279531623626288211765949258916047124642669459480728122908") } 88 | { Fr::is_field() } 89 | OP_VERIFY 90 | // t2w 91 | { Fr::push_dec("12092130080251498309415337127155404037148503145602589831662396526189421234148") } 92 | { Fr::is_field() } 93 | OP_VERIFY 94 | // inv 95 | { Fr::push_dec("21247383512588455895834686692756529012394058115069710447132959660051940541361") } 96 | { Fr::is_field() } 97 | }; 98 | println!("fflonk.check_format = {} bytes", script.len()); 99 | let exec_result = execute_script(script); 100 | assert!(exec_result.success); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/fflonk/checkpairing_miller_loop.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::bn254::ell_coeffs::G2Prepared; 4 | use crate::bn254::fp254impl::Fp254Impl; 5 | use crate::bn254::fq::Fq; 6 | use crate::bn254::fq12::Fq12; 7 | use crate::bn254::pairing::Pairing; 8 | use crate::bn254::utils::{self, fq12_push}; 9 | use crate::treepp::*; 10 | use ark_bn254::Bn254; 11 | use ark_ec::pairing::Pairing as ArkPairing; 12 | use ark_ec::{AffineRepr, CurveGroup}; 13 | 14 | use num_bigint::BigUint; 15 | use std::ops::Neg; 16 | use std::str::FromStr; 17 | 18 | #[test] 19 | fn test_checkpairing_miller_loop() { 20 | let projective = ark_bn254::G1Projective::new( 21 | ark_bn254::Fq::from_str( 22 | "21025932300722401404248737517866966587837387913191004025854702115722286998035", 23 | ) 24 | .unwrap(), 25 | ark_bn254::Fq::from_str( 26 | "5748766770337880144484917096976043621609890780406924686031233755006782215858", 27 | ) 28 | .unwrap(), 29 | ark_bn254::Fq::from_str( 30 | "18747233771850556311508953762939425433543524671221692065979284256379095132287", 31 | ) 32 | .unwrap(), 33 | ); 34 | let affine = projective.into_affine(); 35 | 36 | let a = ark_bn254::g2::G2Affine::new( 37 | ark_bn254::Fq2::new( 38 | ark_bn254::Fq::from_str( 39 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 40 | ) 41 | .unwrap(), 42 | ark_bn254::Fq::from_str( 43 | "11559732032986387107991004021392285783925812861821192530917403151452391805634", 44 | ) 45 | .unwrap(), 46 | ), 47 | ark_bn254::Fq2::new( 48 | ark_bn254::Fq::from_str( 49 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 50 | ) 51 | .unwrap(), 52 | ark_bn254::Fq::from_str( 53 | "4082367875863433681332203403145435568316851327593401208105741076214120093531", 54 | ) 55 | .unwrap(), 56 | ), 57 | ); 58 | let a_prepared = G2Prepared::from(a); 59 | 60 | let b = ark_bn254::g2::G2Affine::new( 61 | ark_bn254::Fq2::new( 62 | ark_bn254::Fq::from_str( 63 | "21831381940315734285607113342023901060522397560371972897001948545212302161822", 64 | ) 65 | .unwrap(), 66 | ark_bn254::Fq::from_str( 67 | "17231025384763736816414546592865244497437017442647097510447326538965263639101", 68 | ) 69 | .unwrap(), 70 | ), 71 | ark_bn254::Fq2::new( 72 | ark_bn254::Fq::from_str( 73 | "2388026358213174446665280700919698872609886601280537296205114254867301080648", 74 | ) 75 | .unwrap(), 76 | ark_bn254::Fq::from_str( 77 | "11507326595632554467052522095592665270651932854513688777769618397986436103170", 78 | ) 79 | .unwrap(), 80 | ), 81 | ); 82 | let b_prepared = G2Prepared::from(b); 83 | 84 | let dual_miller_loop = Pairing::dual_miller_loop(&a_prepared, &b_prepared); 85 | 86 | let w2 = ark_bn254::g1::G1Affine::new( 87 | ark_bn254::Fq::from_str( 88 | "11695827642347470645483614914520090101440686332033956264171712726147972703435", 89 | ) 90 | .unwrap(), 91 | ark_bn254::Fq::from_str( 92 | "8930092616903485317239646434389939466400752538134075201209141980838088395614", 93 | ) 94 | .unwrap(), 95 | ); 96 | 97 | let a_proj = ark_bn254::G2Projective::from(a); 98 | let b_proj = ark_bn254::G2Projective::from(b); 99 | 100 | let c = Bn254::multi_miller_loop([affine.neg(), w2], [a_proj, b_proj]).0; 101 | 102 | let script = script! { 103 | // push A1 104 | { Fq::push_u32_le(&BigUint::from(affine.x().unwrap()).to_u32_digits()) } 105 | { Fq::push_u32_le(&BigUint::from(affine.y().unwrap()).to_u32_digits()) } 106 | { Fq::neg(0) } 107 | 108 | // push W2 109 | { Fq::push_dec("11695827642347470645483614914520090101440686332033956264171712726147972703435") } 110 | { Fq::push_dec("8930092616903485317239646434389939466400752538134075201209141980838088395614") } 111 | 112 | { dual_miller_loop.clone() } 113 | { fq12_push(c) } 114 | { Fq12::equalverify() } 115 | OP_TRUE 116 | }; 117 | 118 | println!("fflonk.checkpairing_miller_loop = {} bytes", script.len()); 119 | 120 | let exec_result = execute_script(script); 121 | assert!(exec_result.success); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/u32/u32_rshift.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::{ 4 | treepp::{script, Script}, 5 | u32::u32_rrot::u8_extract_hbit, 6 | }; 7 | use core::panic; 8 | 9 | pub fn post_process(offset: usize) -> Script { 10 | assert!(offset < 4); 11 | let res: Script = match offset { 12 | 0 => script! { 13 | OP_FROMALTSTACK //[c+cD] 14 | OP_FROMALTSTACK //[c+cD, b+bC] 15 | OP_FROMALTSTACK //[c+cD, b+bC, a+cB] 16 | OP_FROMALTSTACK //[c+cD, b+bC, a+cB, cA] 17 | OP_SWAP //[c+cD, b+bC, cA, a+cB] 18 | OP_2SWAP //[cA, a+cB, c+cD, b+bC] 19 | OP_SWAP //[cA, a+cB, b+bC, c+cD] 20 | }, 21 | 1 => script! { 22 | OP_FROMALTSTACK // [c+cD] 23 | OP_DROP // [] 24 | 0 // [0] 25 | OP_FROMALTSTACK // [0,b+bC] 26 | OP_FROMALTSTACK // [0,b+bC,a+cB] 27 | OP_FROMALTSTACK // [0,b+bC,a+cB,cA] 28 | OP_SWAP // [0,b+bC,cA,a+cB] 29 | OP_ROT // [0,cA,a+cB,b+bC] 30 | }, 31 | 2 => script! { 32 | OP_FROMALTSTACK // [c+cD] 33 | OP_DROP // [] 34 | 0 // [0] 35 | OP_FROMALTSTACK // [0,b+bC] 36 | OP_DROP // [0] 37 | 0 // [0, 0] 38 | OP_FROMALTSTACK // [0,0,a+cB] 39 | OP_FROMALTSTACK // [0,0,a+cB,cA] 40 | OP_SWAP // [0,0,cA,a+cB] 41 | }, 42 | 3 => script! { 43 | OP_FROMALTSTACK // [c+cD] 44 | OP_DROP // [] 45 | 0 // [0] 46 | OP_FROMALTSTACK // [0,b+bC] 47 | OP_DROP // [0] 48 | 0 // [0, 0] 49 | OP_FROMALTSTACK // [0,0,a+cB] 50 | OP_DROP // [0,0] 51 | 0 // [0,0,0] 52 | OP_FROMALTSTACK // [0,0,0,cA] 53 | }, 54 | _ => panic!("offset out of range"), 55 | }; 56 | res 57 | } 58 | pub fn specific_optimize_rshift(shift_num: usize) -> Option