-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
339 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
// } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |