Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejka committed May 1, 2024
1 parent 6254182 commit c25511f
Show file tree
Hide file tree
Showing 2 changed files with 339 additions and 17 deletions.
338 changes: 338 additions & 0 deletions onchain/src/bip340.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
use core::to_byte_array::AppendFormattedToByteArray;
use core::byte_array::ByteArrayTrait;
use core::traits::Into;
use core::option::OptionTrait;
use core::starknet::SyscallResultTrait;
use core::sha256::compute_sha256_byte_array;
use core::debug::print_byte_array_as_string;

// bip340 implementation
// references:
// Schnorr signatures explained:
// https://www.youtube.com/watch?v=wjACBRJDfxc&ab_channel=Bitcoinology
// NIP-01:
// https://github.com/nostr-protocol/nips/blob/master/01.md
// BIP-340:
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
// reference implementation:
// https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py

use starknet::{secp256k1::{Secp256k1Point}, secp256_trait::{Secp256Trait, Secp256PointTrait},};

const TWO_POW_32: u128 = 0x100000000;
const TWO_POW_64: u128 = 0x10000000000000000;
const TWO_POW_96: u128 = 0x1000000000000000000000000;

fn hash_challenge<
Secp256Point,
+Drop<Secp256Point>,
+Secp256PointTrait<Secp256Point>,
impl Secp256Impl: Secp256Trait<Secp256Point>
>(
rx: u256, px: u256, m: ByteArray
) -> u256 {
// sha256(tag)
let [x0, x1, x2, x3, x4, x5, x6, x7] = compute_sha256_byte_array(@"BIP0340/challenge");

// sha256(tag) || sha256(tag) || bytes(r) || bytes(pk) || m
let mut ba = Default::default();
// sha256(tag)
ba.append_word(x0.into(), 4);
ba.append_word(x1.into(), 4);
ba.append_word(x2.into(), 4);
ba.append_word(x3.into(), 4);
ba.append_word(x4.into(), 4);
ba.append_word(x5.into(), 4);
ba.append_word(x6.into(), 4);
ba.append_word(x7.into(), 4);
// sha256(tag)
ba.append_word(x0.into(), 4);
ba.append_word(x1.into(), 4);
ba.append_word(x2.into(), 4);
ba.append_word(x3.into(), 4);
ba.append_word(x4.into(), 4);
ba.append_word(x5.into(), 4);
ba.append_word(x6.into(), 4);
ba.append_word(x7.into(), 4);
// bytes(r)
ba.append_word(rx.high.into(), 16);
ba.append_word(rx.low.into(), 16);
// bytes(px)
ba.append_word(px.high.into(), 16);
ba.append_word(px.low.into(), 16);
// m
ba.append(@m);

// println!("tagged: {:?}", ba);

// let sha_u256: u256 = sha.into();
// println!("sha: {:?}", sha_u256);

let [x0, x1, x2, x3, x4, x5, x6, x7] = compute_sha256_byte_array(@ba);

u256 {
high: x0.into() * TWO_POW_96
+ x1.into() * TWO_POW_64
+ x2.into() * TWO_POW_32
+ x3.into(),
low: x4.into() * TWO_POW_96
+ x5.into() * TWO_POW_64
+ x6.into() * TWO_POW_32
+ x7.into(),
}
}

fn generic_verify<
Secp256Point,
+Drop<Secp256Point>,
+Secp256PointTrait<Secp256Point>,
impl Secp256Impl: Secp256Trait<Secp256Point>,
>(
px: u256, rx: u256, s: u256, m: ByteArray
) -> bool {
// println!("px: {:?}", px);
// println!("rx: {:?}", rx);
// println!("s: {:?}", s);

// p - field size, n - curve order
// point P for which x(P) = px and has_even_y(P),
let P = Secp256Impl::secp256_ec_get_point_from_x_syscall(px, false).unwrap_syscall().unwrap();

// let (Px, Py) = P.get_coordinates().unwrap_syscall();
// println!("P: {:?}, {:?}", Px, Py);
// true

// TODO:
// if (P is None) or (r >= p) or (s >= n):
// debug_print_vars()
// return False

// e = int(hashBIP0340/challenge(bytes(r) || bytes(P) || m)) mod n.
let e = hash_challenge::<Secp256Point>(rx, px, m) % Secp256Impl::get_curve_size();

let G = Secp256Impl::get_generator_point();

// R = s⋅G - e⋅P
let p1 = G.mul(s).unwrap_syscall();
let minus_e = Secp256Impl::get_curve_size() - e;
let p2 = P.mul(minus_e).unwrap_syscall();

let R = p1.add(p2).unwrap_syscall();

let (Rx, Ry) = R.get_coordinates().unwrap_syscall();

// println!("e: {:?}", e);
// println!("Rx: {:?}", Rx);
// println!("rx: {:?}", rx);
// println!("Ry: {:?}", Ry);
// println!("Ry % 2 == 0: {:?}", Ry % 2 == 0);

!(Rx == 0 && Ry == 0) && Ry % 2 == 0 && Rx == rx
}

pub fn verify(px: u256, rx: u256, s: u256, m: ByteArray) -> bool {
generic_verify::<Secp256k1Point>(px, rx, s, m)
}


#[cfg(test)]
mod tests {
use core::clone::Clone;
use core::option::OptionTrait;
use core::byte_array::ByteArrayTrait;
use core::traits::Into;
use super::verify;

impl U256IntoByteArray of Into<u256, ByteArray> {
fn into(self: u256) -> ByteArray {
let mut ba = Default::default();
ba.append_word(self.high.into(), 16);
ba.append_word(self.low.into(), 16);
ba
}
}

// test data adapted from: https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv

#[test]
fn test_0() {
let px: u256 = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9;
let rx: u256 = 0xe907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca8215;
let s: u256 = 0x25f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0;
let m: u256 = 0x0;
assert_eq!(verify(px, rx, s, m.into()), true);
}

#[test]
fn test_1() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x6896bd60eeae296db48a229ff71dfe071bde413e6d43f917dc8dcf8c78de3341;
let s: u256 = 0x8906d11ac976abccb20b091292bff4ea897efcb639ea871cfa95f6de339e4b0a;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), true);
}

#[test]
fn test_2() {
let px: u256 = 0xdd308afec5777e13121fa72b9cc1b7cc0139715309b086c960e18fd969774eb8;
let rx: u256 = 0x5831aaeed7b44bb74e5eab94ba9d4294c49bcf2a60728d8b4c200f50dd313c1b;
let s: u256 = 0xab745879a5ad954a72c45a91c3a51d3c7adea98d82f8481e0e1e03674a6f3fb7;
let m: u256 = 0x7e2d58d8b3bcdf1abadec7829054f90dda9805aab56c77333024b9d0a508b75c;

assert_eq!(verify(px, rx, s, m.into()), true);
}

#[test]
fn test_3() {
let px: u256 = 0x25d1dff95105f5253c4022f628a996ad3a0d95fbf21d468a1b33f8c160d8f517;
let rx: u256 = 0x7eb0509757e246f19449885651611cb965ecc1a187dd51b64fda1edc9637d5ec;
let s: u256 = 0x97582b9cb13db3933705b32ba982af5af25fd78881ebb32771fc5922efc66ea3;
let m: u256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

assert_eq!(verify(px, rx, s, m.into()), true);
}

#[test]
fn test_4() {
let px: u256 = 0xd69c3509bb99e412e68b0fe8544e72837dfa30746d8be2aa65975f29d22dc7b9;
let rx: u256 = 0x3b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63;
let s: u256 = 0x76afb1548af603b3eb45c9f8207dee1060cb71c04e80f593060b07d28308d7f4;
let m: u256 = 0x4df3c3f68fcc83b27e9d42c90431a72499f17875c81a599b566c9889b9696703;

assert_eq!(verify(px, rx, s, m.into()), true);
}

#[test]
fn test_5() {
let px: u256 = 0xeefdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34;
let rx: u256 = 0x6cff5c3ba86c69ea4b7376f31a9bcb4f74c1976089b2d9963da2e5543e177769;
let s: u256 = 0x69e89b4c5564d00349106b8497785dd7d1d713a8ae82b32fa79d5f7fc407d39b;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_6() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0xfff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556;
let s: u256 = 0x3cc27944640ac607cd107ae10923d9ef7a73c643e166be5ebeafa34b1ac553e2;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;

assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_7() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x1fa62e331edbc21c394792d2ab1100a7b432b013df3f6ff4f99fcb33e0e1515f;
let s: u256 = 0x28890b3edb6e7189b630448b515ce4f8622a954cfe545735aaea5134fccdb2bd;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;

assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_8() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x6cff5c3ba86c69ea4b7376f31a9bcb4f74c1976089b2d9963da2e5543e177769;
let s: u256 = 0x961764b3aa9b2ffcb6ef947b6887a226e8d7c93e00c5ed0c1834ff0d0c2e6da6;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;

assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_9() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x0;
let s: u256 = 0x123dda8328af9c23a94c1feecfd123ba4fb73476f0d594dcb65c6425bd186051;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;

assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_10() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x1;
let s: u256 = 0x7615fbaf5ae28864013c099742deadb4dba87f11ac6754f93780d5a1837cf197;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;

assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_11() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x4a298dacae57395a15d0795ddbfd1dcb564da82b0f269bc70a74f8220429ba1d;
let s: u256 = 0x69e89b4c5564d00349106b8497785dd7d1d713a8ae82b32fa79d5f7fc407d39b;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_12() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f;
let s: u256 = 0x69e89b4c5564d00349106b8497785dd7d1d713a8ae82b32fa79d5f7fc407d39b;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_13() {
let px: u256 = 0xdff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659;
let rx: u256 = 0x6cff5c3ba86c69ea4b7376f31a9bcb4f74c1976089b2d9963da2e5543e177769;
let s: u256 = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_14() {
let px: u256 = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30;
let rx: u256 = 0x6cff5c3ba86c69ea4b7376f31a9bcb4f74c1976089b2d9963da2e5543e177769;
let s: u256 = 0x69e89b4c5564d00349106b8497785dd7d1d713a8ae82b32fa79d5f7fc407d39b;
let m: u256 = 0x243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89;
assert_eq!(verify(px, rx, s, m.into()), false);
}

#[test]
fn test_15() {
let px: u256 = 0x778caa53b4393ac467774d09497a87224bf9fab6f6e68b23086497324d6fd117;
let rx: u256 = 0x71535db165ecd9fbbc046e5ffaea61186bb6ad436732fccc25291a55895464cf;
let s: u256 = 0x6069ce26bf03466228f19a3a62db8a649f2d560fac652827d1af0574e427ab63;
let m = "";
assert_eq!(verify(px, rx, s, m), true);
}

#[test]
fn test_16() {
let px: u256 = 0x778caa53b4393ac467774d09497a87224bf9fab6f6e68b23086497324d6fd117;
let rx: u256 = 0x8a20a0afef64124649232e0693c583ab1b9934ae63b4c3511f3ae1134c6a303;
let s: u256 = 0xea3173bfea6683bd101fa5aa5dbc1996fe7cacfc5a577d33ec14564cec2bacbf;
let m = "\x11";
assert_eq!(verify(px, rx, s, m), true);
}

#[test]
fn test_17() {
let px: u256 = 0x778caa53b4393ac467774d09497a87224bf9fab6f6e68b23086497324d6fd117;
let rx: u256 = 0x5130f39a4059b43bc7cac09a19ece52b5d8699d1a71e3c52da9afdb6b50ac370;
let s: u256 = 0xc4a482b77bf960f8681540e25b6771ece1e5a37fd80e5a51897c5566a97ea5a5;
let m = "\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11";

assert_eq!(verify(px, rx, s, m), true);
}
// TODO: message is too long!
// #[test]
// fn test_18() {
// let px: u256 = 0x778caa53b4393ac467774d09497a87224bf9fab6f6e68b23086497324d6fd117 ;
// let rx: u256 = 0x403b12b0d8555a344175ea7ec746566303321e5dbfa8be6f091635163eca79a8 ;
// let s: u256 = 0x585ed3e3170807e7c03b720fc54c7b23897fcba0e9d0b4a06894cfd249f22367 ;
// let m: u256 =
//
// 0x99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
// assert_eq!(verify(px, rx, s, m.into()), true);
// }
}
18 changes: 1 addition & 17 deletions onchain/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,17 +1 @@
fn main() -> u32 {
0
}

fn say_hi() -> u32 {
0
}

#[cfg(test)]
mod tests {
use super::say_hi;

#[test]
fn it_works() {
assert(say_hi() == 0, 'it works!');
}
}
pub mod bip340;

0 comments on commit c25511f

Please sign in to comment.