From 127763771ba3425e845f22fc0b7ca208e6c961b2 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Fri, 25 Oct 2024 17:58:20 +0300 Subject: [PATCH 01/10] feat: updated to use noir_bigcurve library --- crates/plume/Nargo.toml | 3 +- crates/plume/src/constants.nr | 9 - crates/plume/src/ec_ops.nr | 92 ----- crates/plume/src/expand_message_xmd.nr | 149 ++++---- crates/plume/src/hash_to_curve.nr | 73 ++-- crates/plume/src/hash_to_field.nr | 65 ++-- crates/plume/src/iso_map.nr | 178 ++++----- crates/plume/src/lib.nr | 504 +++++++++++++++---------- crates/plume/src/map_to_curve.nr | 158 +++++--- crates/plume/src/utils.nr | 35 -- crates/use/Nargo.toml | 3 +- crates/use/Prover.toml | 10 +- crates/use/src/main.nr | 24 +- etc/gen.sage | 7 +- etc/main.sage | 12 +- 15 files changed, 688 insertions(+), 634 deletions(-) delete mode 100644 crates/plume/src/constants.nr delete mode 100644 crates/plume/src/ec_ops.nr delete mode 100644 crates/plume/src/utils.nr diff --git a/crates/plume/Nargo.toml b/crates/plume/Nargo.toml index 6a38355..1c0868e 100644 --- a/crates/plume/Nargo.toml +++ b/crates/plume/Nargo.toml @@ -7,4 +7,5 @@ description = "PLUME implementation in Noir." compiler_version = ">=0.35.0" [dependencies] -bignum = {tag = "v0.3.6", git = "https://github.com/noir-lang/noir-bignum"} \ No newline at end of file +bignum = {tag = "v0.3.7", git = "https://github.com/noir-lang/noir-bignum"} +noir_bigcurve = {tag = "v0.4", git = "https://github.com/noir-lang/noir_bigcurve"} \ No newline at end of file diff --git a/crates/plume/src/constants.nr b/crates/plume/src/constants.nr deleted file mode 100644 index 627c481..0000000 --- a/crates/plume/src/constants.nr +++ /dev/null @@ -1,9 +0,0 @@ -use bignum::BigNum; -use bignum::fields::secp256k1Fq::Secp256k1_Fq_Params; - -pub type Fq = BigNum<3, Secp256k1_Fq_Params>; - -pub global MSG_LEN: u32 = 32; -pub global PLUME_MSG_LEN: u32 = MSG_LEN + 33; // Because a point is added, which is compressed to 33 bytes - -pub global ZERO: Fq = BigNum::from_array([0, 0, 0]); diff --git a/crates/plume/src/ec_ops.nr b/crates/plume/src/ec_ops.nr deleted file mode 100644 index 25457f5..0000000 --- a/crates/plume/src/ec_ops.nr +++ /dev/null @@ -1,92 +0,0 @@ -use crate::constants::ZERO; -use bignum::BigNum; -use crate::constants::Fq; - -pub type Point = (Fq, Fq); - -// Operations taken from the http://delta.cs.cinvestav.mx/~francisco/cripto/ellipticbg.pdf doc -pub fn point_add(p0: Point, p1: Point) -> Point { - let (x0, y0) = p0; - let (x1, y1) = p1; - - let lambda = (y1 - y0) / (x1 - x0); - let x2 = lambda * lambda - x0 - x1; - let y2 = lambda * (x0 - x2) - y0; - (x2, y2) -} - -fn double_point(p: Point) -> Point { - let (x, y) = p; - let two = BigNum::from_array([2, 0, 0]); - let three = BigNum::from_array([3, 0, 0]); - - let lambda = (three * x * x) / (two * y); - let x3 = lambda * lambda - two * x; - let y3 = lambda * (x - x3) - y; - (x3, y3) -} - -pub fn point_mul(scalar: [u8; 32], mut p: Point) -> Point { - let mut res = (ZERO, ZERO); - let mut first_add = true; - - for i in 0..32 { - for j in 0..8 { - if scalar[i] & (1 << j) != 0 { - if first_add { - res = p; - first_add = false; - } else { - res = point_add(res, p); - } - } - p = double_point(p); - } - } - res -} - -#[test] -fn test_point_add_with_msg_abc() { - let p0 = ( - BigNum::from_array([0x6604ccbbbadad8523b8fc38a5322d7, 0x9432d426845fb19857d1b3a9172243, 0x7dd]), BigNum::from_array([0xe0e523bbaf1bed4014a467122eb33f, 0x88ef5138cffe3277bbd590b8550bcb, 0x6045]) - ); - let p1 = ( - BigNum::from_array([0x6b8dac05f8491eb88764fc65321f78, 0x9794d15d4e77dde751e06c18278204, 0xe9ef]), BigNum::from_array([0x2dd76314aa41f012919fe8e7f717b3, 0xce53670d5314bf236ee2c871455c56, 0xcb07]) - ); - - let actual_p = point_add(p0, p1); - let expected_p = ( - BigNum::from_array([0xb6ecf9f9205760bd9ff11fb3cb2c4b, 0xe01eab42db296b512293120c6cee72, 0x3377]), BigNum::from_array([0xfb6116f94688d487c6c7b9c8371f6, 0x890f33efebd1044d382a01b1bee090, 0x7f95]) - ); - assert(actual_p == expected_p); -} - -#[test] -fn test_double_point() { - let p = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) - ); - - let actual_p = double_point(p); - let expected_p = ( - BigNum::from_array([0xd8d0efa7dcf721e0dba86a00aec8cd, 0x688008eb81d1e7e3a81df0e34120a0, 0x9ecb]), BigNum::from_array([0xa6480d893bc063ee11ca12ca8e3c77, 0x7d646834bfcb7145349ff0128d0b67, 0x7a40]) - ); - assert(actual_p == expected_p); -} - -#[test] -fn point_mul_with_scalar() { - let p = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) - ); - let scalar = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - - let actual_p = point_mul(scalar, p); - let expected_p: Point = ( - BigNum::from_array([0xc5a66473a45c1e626f1d0c67e55830, 0x3ed28172ef8adde4b9e0c2cce745fc, 0x57bc]), BigNum::from_array([0x9f3ae67ea38fa891d6087fe59ecb73, 0x41488d58f33ae46edd2188e111609f, 0x6a2f]) - ); - assert(actual_p == expected_p); -} diff --git a/crates/plume/src/expand_message_xmd.nr b/crates/plume/src/expand_message_xmd.nr index 933cac0..e6b54d5 100644 --- a/crates/plume/src/expand_message_xmd.nr +++ b/crates/plume/src/expand_message_xmd.nr @@ -1,48 +1,53 @@ +/* + Expand message XMD with SHA-256. + + See the link below for more details: + + https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-expand_message_xmd +*/ + use std::hash::sha256; -use crate::constants::PLUME_MSG_LEN; -fn get_dst_prime() -> [u8] { - [ - 81, 85, 85, 88, 45, 86, 48, 49, 45, 67, 83, 48, 50, 45, 119, 105, 116, - 104, 45, 115, 101, 99, 112, 50, 53, 54, 107, 49, 95, 88, 77, 68, 58, - 83, 72, 65, 45, 50, 53, 54, 95, 83, 83, 87, 85, 95, 82, 79, 95, 49 - ] +pub fn expand_message_xmd(msg: [u8; N]) -> [u8; 96] { + let b0 = msg_prime(msg); + let b1 = hash_b(1, b0); + let b2 = hash_bi(2, b0, b1); + let b3 = hash_bi(3, b0, b2); + + let mut out = [0 as u8; 96]; + for i in 0..32 { + out[i] = b1[i]; + } + for i in 0..32 { + out[32 + i] = b2[i]; + } + for i in 0..32 { + out[64 + i] = b3[i]; + } + + out } fn msg_prime(msg: [u8; N]) -> [u8; 32] { - let lib_str = [0, 96]; - let mut msg_prime = [0 as u8; PLUME_MSG_LEN + 64 + 2 + 50 + 1]; // padding size - let dst_prime = get_dst_prime(); + let mut preimage = [0 as u8; 64 + N + 2 + 1 + 50]; for i in 0..N { - msg_prime[64 + i] = msg[i]; - } - for i in 0..2 { - msg_prime[64 + N + i] = lib_str[i]; + preimage[64 + i] = msg[i]; } - msg_prime[64 + N + 2] = 0; - // msg_prme = z_pad || msg || lib_str || 0 || dst_prime - for i in 0..dst_prime.len() { - msg_prime[64 + N + 2 + 1 + i] = dst_prime[i]; + let lib_str = [0, 96]; + for i in 0..lib_str.len() { + preimage[64 + N + i] = lib_str[i]; } - sha256(msg_prime) -} -fn hash_b(b_idx: u8, b: [u8; 32]) -> [u8; 32] { - assert(b_idx < 8); - let dst_prime = get_dst_prime(); - - let mut res = [0; 32 + 1 + 50]; // Num preimage bytes - for i in 0..32 { - res[i] = b[i]; - } - res[32] = b_idx; + preimage[64 + N + 2] = 0; + let dst_prime = dst_prime(); for i in 0..dst_prime.len() { - res[32 + 1 + i] = dst_prime[i]; + preimage[64 + N + 2 + 1 + i] = dst_prime[i]; } - sha256(res) + + sha256(preimage) } fn hash_bi(b_idx: u8, b0: [u8; 32], b1: [u8; 32]) -> [u8; 32] { @@ -52,45 +57,53 @@ fn hash_bi(b_idx: u8, b0: [u8; 32], b1: [u8; 32]) -> [u8; 32] { for i in 0..32 { res[i] = b0[i] ^ b1[i]; } + hash_b(b_idx, res) } -// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-expand_message_xmd -pub fn expand_message_xmd(msg: [u8; N]) -> [u8; 96] { - let b0 = msg_prime(msg); - let b1 = hash_b(1, b0); - let b2 = hash_bi(2, b0, b1); - let b3 = hash_bi(3, b0, b2); +fn hash_b(b_idx: u8, b: [u8; 32]) -> [u8; 32] { + assert(b_idx < 8); + let mut preimage = [0; 32 + 1 + 50]; - // Or maybe reverse bits in bi - let mut out = [0 as u8; 96]; for i in 0..32 { - out[i] = b1[i]; + preimage[i] = b[i]; } - for i in 0..32 { - out[32 + i] = b2[i]; - } - for i in 0..32 { - out[64 + i] = b3[i]; + + preimage[32] = b_idx; + + let dst_prime = dst_prime(); + for i in 0..dst_prime.len() { + preimage[32 + 1 + i] = dst_prime[i]; } - out + + sha256(preimage) +} + +// ****************** CONSTANTS ****************** // +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-expand_message_xmdsha-256 + +fn dst_prime() -> [u8; 50] { + [ + 81, 85, 85, 88, 45, 86, 48, 49, 45, 67, 83, 48, 50, 45, 119, 105, 116, + 104, 45, 115, 101, 99, 112, 50, 53, 54, 107, 49, 95, 88, 77, 68, 58, + 83, 72, 65, 45, 50, 53, 54, 95, 83, 83, 87, 85, 95, 82, 79, 95, 49 + ] } -// Failed, if PLUME_MSG_LEN != 3 -/* #[test] fn test_b0() { - let msg = [97, 98, 99]; + let msg = [97, 98, 99]; // "abc" + + let actual_b0 = msg_prime(msg); - let b0 = msg_prime(msg); let expected_b0 = [ 99, 4, 75, 36, 124, 254, 65, 234, 207, 65, 212, 122, 206, 186, 87, 48, 157, 28, 243, 255, 59, 178, 30, 40, 136, 85, 202, 99, 135, 177, 127, 169 ]; - assert(b0 == expected_b0); + + assert(actual_b0 == expected_b0); } -*/ #[test] fn test_b1() { @@ -100,13 +113,15 @@ fn test_b1() { 127, 169 ]; - let b1 = hash_b(1, b0); + let actual_b1 = hash_b(1, b0); + let expected_b1 = [ 232, 52, 124, 173, 72, 171, 78, 49, 157, 123, 39, 85, 32, 234, 129, 207, 18, 138, 171, 93, 54, 121, 161, 247, 96, 30, 59, 222, 172, 154, 81, 208 ]; - assert(b1 == expected_b1); + + assert(actual_b1 == expected_b1); } #[test] @@ -122,13 +137,15 @@ fn test_b2() { 81, 208 ]; - let b2 = hash_bi(2, b0, b1); + let actual_b2 = hash_bi(2, b0, b1); + let expected_b2 = [ 197, 77, 255, 208, 84, 39, 78, 219, 36, 136, 85, 230, 17, 144, 196, 98, 167, 187, 97, 236, 186, 142, 64, 10, 154, 118, 213, 174, 1, 78, 135, 255 ]; - assert(b2 == expected_b2); + + assert(actual_b2 == expected_b2); } #[test] @@ -143,24 +160,24 @@ fn test_b3() { 167, 187, 97, 236, 186, 142, 64, 10, 154, 118, 213, 174, 1, 78, 135, 255 ]; - let b3 = hash_bi(3, b0, b2); + let actual_b3 = hash_bi(3, b0, b2); + let expected_b3 = [ 88, 151, 182, 93, 163, 181, 149, 168, 19, 208, 253, 203, 206, 13, 49, 111, 118, 108, 238, 235, 111, 248, 76, 222, 204, 214, 155, 224, 231, 179, 153, 209 ]; - assert(b3 == expected_b3); + + assert(actual_b3 == expected_b3); } -// Failed, if PLUME_MSG_LEN != 3 -/* #[test] fn tests_expand_message_xmd() { - // "abc" message - let msg = [97, 98, 99]; + let msg = [97, 98, 99]; // "abc" + + let actual = expand_message_xmd(msg); - let expand_message_xmd = expand_message_xmd(msg); - let expected_expand_message_xmd = [ + let expected = [ 232, 52, 124, 173, 72, 171, 78, 49, 157, 123, 39, 85, 32, 234, 129, 207, 18, 138, 171, 93, 54, 121, 161, 247, 96, 30, 59, 222, 172, 154, 81, 208, 197, 77, 255, 208, 84, 39, 78, 219, 36, 136, 85, 230, 17, @@ -169,6 +186,6 @@ fn tests_expand_message_xmd() { 203, 206, 13, 49, 111, 118, 108, 238, 235, 111, 248, 76, 222, 204, 214, 155, 224, 231, 179, 153, 209 ]; - assert(expand_message_xmd == expected_expand_message_xmd); + + assert(actual == expected); } -*/ diff --git a/crates/plume/src/hash_to_curve.nr b/crates/plume/src/hash_to_curve.nr index e08af25..c29cc4e 100644 --- a/crates/plume/src/hash_to_curve.nr +++ b/crates/plume/src/hash_to_curve.nr @@ -1,27 +1,34 @@ +/* + secp256k1_XMD:SHA-256_SSWU_RO_ + + Based on the code from the link below: + + https://github.com/geometryxyz/secp256k1_hash_to_curve +*/ + +use noir_bigcurve::curves::secp256k1::Secp256k1; + use crate::hash_to_field::hash_to_field; use crate::map_to_curve::map_to_curve; use crate::iso_map::iso_map; -use crate::ec_ops::{Point, point_add}; -// Based on https://github.com/geometryxyz/secp256k1_hash_to_curve code -pub fn hash_to_curve(msg: [u8; N]) -> Point { +pub fn hash_to_curve(msg: [u8; N]) -> Secp256k1 { let u = hash_to_field(msg); - let q0 = map_to_curve(u.0); - let q1 = map_to_curve(u.1); + let q0 = map_to_curve(u.x); + let q1 = map_to_curve(u.y); - point_add(iso_map(q0), iso_map(q1)) + iso_map(q0) + iso_map(q1) } -/* -// These test cases are commented out because they depend on the PLUME_MSG_LEN constant. -// If the msg.len() in test case is not equal to PLUME_MSG_LEN, then it Failed +// Data for test cases is taken from the link below: +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-secp256k1_xmdsha-256_sswu_r -// Test cases are taken from https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-secp256k1_xmdsha-256_sswu_r #[test] fn test_hash_to_curve_for_empty_msg() { let msg = []; - let (px, py) = hash_to_curve(msg); + + let actual_p = hash_to_curve(msg); let expected_px = [ 70, 19, 235, 223, 45, 133, 181, 183, @@ -35,14 +42,16 @@ fn test_hash_to_curve_for_empty_msg() { 109, 175, 148, 42, 2, 139, 240, 38, 97, 17, 174, 7, 142, 103, 250, 100 ]; - assert(px.to_le_bytes() == expected_px); - assert(py.to_le_bytes() == expected_py); + + assert(actual_p.x.to_le_bytes() == expected_px); + assert(actual_p.y.to_le_bytes() == expected_py); } #[test] fn test_hash_to_curve_for_msg_abc() { - let msg = [97, 98, 99]; - let (px, py) = hash_to_curve(msg); + let msg = [97, 98, 99]; // "abc" + + let actual_p = hash_to_curve(msg); let expected_px = [ 75, 44, 203, 179, 31, 241, 159, 189, @@ -56,15 +65,16 @@ fn test_hash_to_curve_for_msg_abc() { 224, 190, 177, 1, 42, 56, 77, 4, 209, 235, 239, 51, 15, 137, 149, 127 ]; - assert(px.to_le_bytes() == expected_px); - assert(py.to_le_bytes() == expected_py); + + assert(actual_p.x.to_le_bytes() == expected_px); + assert(actual_p.y.to_le_bytes() == expected_py); } #[test] fn test_hash_to_curve_for_msg_abcdef0123456789() { - // msg.len() = 16 let msg = [97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; - let (px, py) = hash_to_curve(msg); + + let actual_p = hash_to_curve(msg); let expected_px = [ 58, 14, 75, 103, 208, 36, 179, 72, @@ -78,13 +88,13 @@ fn test_hash_to_curve_for_msg_abcdef0123456789() { 64, 156, 56, 244, 252, 96, 139, 80, 196, 195, 212, 133, 96, 71, 54, 68 ]; - assert(px.to_le_bytes() == expected_px); - assert(py.to_le_bytes() == expected_py); + + assert(actual_p.x.to_le_bytes() == expected_px); + assert(actual_p.y.to_le_bytes() == expected_py); } #[test] fn test_hash_to_curve_for_msg_q128() { - // msg.len() = 133 let msg = [ 113, 49, 50, 56, 95, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, @@ -97,7 +107,8 @@ fn test_hash_to_curve_for_msg_q128() { 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113 ]; - let (px, py) = hash_to_curve(msg); + + let actual_p = hash_to_curve(msg); let expected_px = [ 233, 144, 24, 228, 2, 177, 114, 127, @@ -111,13 +122,13 @@ fn test_hash_to_curve_for_msg_q128() { 118, 100, 213, 124, 54, 79, 237, 255, 103, 88, 195, 92, 217, 29, 64, 242 ]; - assert(px.to_le_bytes() == expected_px); - assert(py.to_le_bytes() == expected_py); + + assert(actual_p.x.to_le_bytes() == expected_px); + assert(actual_p.y.to_le_bytes() == expected_py); } #[test] fn test_hash_to_curve_for_msg_a512() { - // msg.len() = 517 let msg = [ 97, 53, 49, 50, 95, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, @@ -146,7 +157,8 @@ fn test_hash_to_curve_for_msg_a512() { 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97 ]; - let (px, py) = hash_to_curve(msg); + + let actual_p = hash_to_curve(msg); let expected_px = [ 152, 201, 183, 140, 31, 140, 253, 230, @@ -160,7 +172,8 @@ fn test_hash_to_curve_for_msg_a512() { 204, 33, 34, 38, 78, 210, 169, 86, 47, 241, 27, 24, 182, 238, 70, 132 ]; - assert(px.to_le_bytes() == expected_px); - assert(py.to_le_bytes() == expected_py); + + assert(actual_p.x.to_le_bytes() == expected_px); + assert(actual_p.y.to_le_bytes() == expected_py); } -*/ + diff --git a/crates/plume/src/hash_to_field.nr b/crates/plume/src/hash_to_field.nr index c8ac905..c841cb6 100644 --- a/crates/plume/src/hash_to_field.nr +++ b/crates/plume/src/hash_to_field.nr @@ -1,25 +1,18 @@ -use bignum::BigNum; -use crate::expand_message_xmd::expand_message_xmd; -use crate::constants::Fq; -use crate::ec_ops::Point; +/* + Hashing to a finite field for secp256k1. + + See the link below for more details: -fn bytes_to_registers(ui: [u8; 48]) -> Fq { - let shift = BigNum::from_array([0, 0x100, 0]); - let mut small = [0 as u8; 32]; - let mut big = [0 as u8; 32]; + https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-hashing-to-a-finite-field +*/ - for i in 0..16 { - small[i+16] = ui[i+32]; - } - for i in 0..32 { - big[i] = ui[i]; - } - let res = BigNum::from_be_bytes(big); - res * shift + BigNum::from_be_bytes(small) -} +use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fq}; +use noir_bigcurve::BigCurve; + +use crate::expand_message_xmd::expand_message_xmd; -// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-hashing-to-a-finite-field -pub fn hash_to_field(msg: [u8; N]) -> Point { +pub fn hash_to_field(msg: [u8; N]) -> Secp256k1 { let expand_message_xmd = expand_message_xmd(msg); let mut u0_bytes_to_registers = [0 as u8; 48]; @@ -32,7 +25,23 @@ pub fn hash_to_field(msg: [u8; N]) -> Point { let u0_bytes_to_registers = bytes_to_registers(u0_bytes_to_registers); let u1_bytes_to_registers = bytes_to_registers(u1_bytes_to_registers); - (u0_bytes_to_registers, u1_bytes_to_registers) + + BigCurve { x: u0_bytes_to_registers, y: u1_bytes_to_registers, is_infinity: false } +} + +fn bytes_to_registers(ui: [u8; 48]) -> Secp256k1Fq { + let shift = BigNum::from_array([0, 0x100, 0]); + let mut small = [0 as u8; 32]; + let mut big = [0 as u8; 32]; + + for i in 0..16 { + small[i+16] = ui[i+32]; + } + for i in 0..32 { + big[i] = ui[i]; + } + let res = BigNum::from_be_bytes(big); + res * shift + BigNum::from_be_bytes(small) } #[test] @@ -43,9 +52,11 @@ fn test_u0_bytes_to_registers() { 197, 77, 255, 208, 84, 39, 78, 219, 36, 136, 85, 230, 17, 144, 196, 98 ]; - let u0_bytes_to_registers = bytes_to_registers(u0_bytes); - let expected_u0_bytes_to_registers = BigNum::from_array([0x491f544767e18a4873f397b08a2b61, 0xab5d3679a1f7601e3bdf94ced1f43e, 0x128a]); - assert(u0_bytes_to_registers == expected_u0_bytes_to_registers); + let actual = bytes_to_registers(u0_bytes); + + let expected = BigNum::from_array([0x491f544767e18a4873f397b08a2b61, 0xab5d3679a1f7601e3bdf94ced1f43e, 0x128a]); + + assert(actual == expected); } #[test] @@ -56,7 +67,9 @@ fn test_u1_bytes_to_registers() { 118, 108, 238, 235, 111, 248, 76, 222, 204, 214, 155, 224, 231, 179, 153, 209 ]; - let u1_bytes_to_registers = bytes_to_registers(u1_bytes); - let expected_u1_bytes_to_registers = BigNum::from_array([0x1be76a03518b044daaa0f2e4689e00, 0xb65da3b595a813d0fdcc75c895dc53, 0x5897]); - assert(u1_bytes_to_registers == expected_u1_bytes_to_registers); + let actual = bytes_to_registers(u1_bytes); + + let expected = BigNum::from_array([0x1be76a03518b044daaa0f2e4689e00, 0xb65da3b595a813d0fdcc75c895dc53, 0x5897]); + + assert(actual == expected); } diff --git a/crates/plume/src/iso_map.nr b/crates/plume/src/iso_map.nr index ee51a7b..3836b39 100644 --- a/crates/plume/src/iso_map.nr +++ b/crates/plume/src/iso_map.nr @@ -1,130 +1,106 @@ -use bignum::BigNum; -use crate::constants::Fq; -use crate::ec_ops::Point; - /* -k_(1,3) * x^3 + -k_(1,2) * x^2 + -k_(1,1) * x + -k_(1,0) -*/ -fn x_num(x: Fq, x_2: Fq, x_3: Fq) -> Fq { - let k1_0 = BigNum::from_array(k_1_0()); - let k1_1 = BigNum::from_array(k_1_1()); - let k1_2 = BigNum::from_array(k_1_2()); - let k1_3 = BigNum::from_array(k_1_3()); - k1_0 + k1_1 * x + k1_2 * x_2 + k1_3 * x_3 -} + 3-isogeny map from E' to E for secp256k1. + + See the link below for more details: -/* -x'^2 + -k_(2,1) * x' + -k_(2,0) + https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-3-isogeny-map-for-secp256k1 */ -fn x_den(x: Fq, x_2: Fq) -> Fq { - let k2_0 = BigNum::from_array(k_2_0()); - let k2_1 = BigNum::from_array(k_2_1()); - x_2 + k2_1 * x + k2_0 -} -/* -k_(3,3) * x'^3 + -k_(3,2) * x'^2 + -k_(3,1) * x' + -k_(3,0) -*/ -fn y_num(x: Fq, x_2: Fq, x_3: Fq) -> Fq { - let k3_0 = BigNum::from_array(k_3_0()); - let k3_1 = BigNum::from_array(k_3_1()); - let k3_2 = BigNum::from_array(k_3_2()); - let k3_3 = BigNum::from_array(k_3_3()); - k3_0 + k3_1 * x + k3_2 * x_2 + k3_3 * x_3 -} +use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fq}; +use noir_bigcurve::BigCurve; -/* -x'^3 + -k_(4,2) * x'^2 + -k_(4,1) * x' + -k_(4,0) -*/ -fn y_den(x: Fq, x_2: Fq, x_3: Fq) -> Fq { - let k4_0 = BigNum::from_array(k_4_0()); - let k4_1 = BigNum::from_array(k_4_1()); - let k4_2 = BigNum::from_array(k_4_2()); - k4_0 + k4_1 * x + k4_2 * x_2 + x_3 -} +pub fn iso_map(p: Secp256k1) -> Secp256k1 { + let x2 = p.x * p.x; + let x3 = x2 * p.x; + + let x_num = x_num(p.x, x2, x3); + let x_den = x_den(p.x, x2); + let y_num = y_num(p.x, x2, x3); + let y_den = y_den(p.x, x2, x3); + + let x = (x_num / x_den); + let y = (p.y * y_num / y_den); -// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-3-isogeny-map-for-secp256k1 -pub fn iso_map(p: Point) -> Point { - let (x, y) = p; + BigCurve { x, y, is_infinity: false } +} - // Step 1. Calculate x^2 - // Step 2. Calculate x^3 - let x_2 = x * x; - let x_3 = x_2 * x; +fn x_num(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { + k1_0() + k1_1() * x + k1_2() * x2 + k1_3() * x3 +} - let x_num = x_num(x, x_2, x_3); - let x_den = x_den(x, x_2); - let y_num = y_num(x, x_2, x_3); - let y_den = y_den(x, x_2, x_3); +fn x_den(x: Secp256k1Fq, x2: Secp256k1Fq) -> Secp256k1Fq { + x2 + k2_1() * x + k2_0() +} - let x = (x_num / x_den); - let y = (y * y_num / y_den); - (x, y) +fn y_num(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { + k3_0() + k3_1() * x + k3_2() * x2 + k3_3() * x3 } -#[test] -fn test_iso_map() { - let p = ( - BigNum::from_array([0xf7ae5f23c431edeb6be5bb360925ea, 0xce532d92416a9488104157036455a0, 0x8dec]), BigNum::from_array([0x13d22e4d45e5bef361e486c6a5da4a, 0xae1c326847bd4a133e5dee6b2ca67c, 0xe249]) - ); - let actual_p = iso_map(p); - let expected_p = ( - BigNum::from_array([0x7c2a947a20fd9ad71039f8b0e29ff8, 0x6d261a5e00fe5cf45e827b507643e6, 0xf89d]), BigNum::from_array([0x1ce936d563bc1cee1dcffc806caf57, 0x55e0cc34a9176ead91c6c3acb1aacb, 0xb338]) - ); - assert(actual_p == expected_p); +fn y_den(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { + k4_0() + k4_1() * x + k4_2() * x2 + x3 } -// Constants -fn k_1_0() -> [Field; 3] { - [0xe38e38e38e38e38e38e38daaaaa8c7, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38] +// ****************** CONSTANTS ****************** // + +fn k1_0() -> Secp256k1Fq { + BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa8c7, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]) } -fn k_1_1() -> [Field; 3] { - [0x95d2fc0bf63b92dfff1044f17c6581, 0xd4c80bc321d5b9f315cea7fd44c5d5, 0x7d3] +fn k1_1() -> Secp256k1Fq { + BigNum::from_array([0x95d2fc0bf63b92dfff1044f17c6581, 0xd4c80bc321d5b9f315cea7fd44c5d5, 0x7d3]) } -fn k_1_2() -> [Field; 3] { - [0x506144037c40314ecbd0b53d9dd262, 0x328d23f234e6e2a413deca25caece4, 0x534c] +fn k1_2() -> Secp256k1Fq { + BigNum::from_array([0x506144037c40314ecbd0b53d9dd262, 0x328d23f234e6e2a413deca25caece4, 0x534c]) } -fn k_1_3() -> [Field; 3] { - [0xe38e38e38e38e38e38e38daaaaa88c, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38] +fn k1_3() -> Secp256k1Fq { + BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa88c, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]) } -fn k_2_0() -> [Field; 3] { - [0xcd409542f8487d9fe6b745781eb49b, 0x71193d94918a9ca34ccbb7b640dd86, 0xd357] +fn k2_0() -> Secp256k1Fq { + BigNum::from_array([0xcd409542f8487d9fe6b745781eb49b, 0x71193d94918a9ca34ccbb7b640dd86, 0xd357]) } -fn k_2_1() -> [Field; 3] { - [0xd36b641f5e41bbc52a56612a8c6d14, 0xc6f64383dc1df7c4b2d51b54225406, 0xedad] +fn k2_1() -> Secp256k1Fq { + BigNum::from_array([0xd36b641f5e41bbc52a56612a8c6d14, 0xc6f64383dc1df7c4b2d51b54225406, 0xedad]) } -fn k_3_0() -> [Field; 3] { - [0x684bda12f684bda12f684b8e38e23c, 0x12f684bda12f684bda12f684bda12f, 0x4bda] +fn k3_0() -> Secp256k1Fq { + BigNum::from_array([0x684bda12f684bda12f684b8e38e23c, 0x12f684bda12f684bda12f684bda12f, 0x4bda]) } -fn k_3_1() -> [Field; 3] { - [0x7ab046d686da6fdffc90fc201d71a3, 0xc32d5cb7c0fa9d0a54b12a0a6d564, 0xc75e] +fn k3_1() -> Secp256k1Fq { + BigNum::from_array([0x7ab046d686da6fdffc90fc201d71a3, 0xc32d5cb7c0fa9d0a54b12a0a6d564, 0xc75e]) } -fn k_3_2() -> [Field; 3] { - [0x2830a201be2018a765e85a9ecee931, 0x194691f91a73715209ef6512e57672, 0x29a6] +fn k3_2() -> Secp256k1Fq { + BigNum::from_array([0x2830a201be2018a765e85a9ecee931, 0x194691f91a73715209ef6512e57672, 0x29a6]) } -fn k_3_3() -> [Field; 3] { - [0xa12f684bda12f684bda12f38e38d84, 0x4bda12f684bda12f684bda12f684bd, 0x2f68] +fn k3_3() -> Secp256k1Fq { + BigNum::from_array([0xa12f684bda12f684bda12f38e38d84, 0x4bda12f684bda12f684bda12f684bd, 0x2f68]) } -fn k_4_0() -> [Field; 3] { - [0xfffffffffffffffffffffefffff93b, 0xffffffffffffffffffffffffffffff, 0xffff] +fn k4_0() -> Secp256k1Fq { + BigNum::from_array([0xfffffffffffffffffffffefffff93b, 0xffffffffffffffffffffffffffffff, 0xffff]) } -fn k_4_1() -> [Field; 3] { - [0x67c1bfc8e8d978dfb425d2685c2573, 0x534bb8bdb49fd5e9e6632722c29894, 0x7a06] +fn k4_1() -> Secp256k1Fq { + BigNum::from_array([0x67c1bfc8e8d978dfb425d2685c2573, 0x534bb8bdb49fd5e9e6632722c29894, 0x7a06]) } -fn k_4_2() -> [Field; 3] { - [0x3d21162f0d6299a7bf8192bfd2a76f, 0xaa716545ca2cf3a70c3fa8fe337e0a, 0x6484] +fn k4_2() -> Secp256k1Fq { + BigNum::from_array([0x3d21162f0d6299a7bf8192bfd2a76f, 0xaa716545ca2cf3a70c3fa8fe337e0a, 0x6484]) +} + +#[test] +fn test_iso_map() { + let p: Secp256k1 = BigCurve { + x: BigNum::from_array([0xf7ae5f23c431edeb6be5bb360925ea, 0xce532d92416a9488104157036455a0, 0x8dec]), + y: BigNum::from_array([0x13d22e4d45e5bef361e486c6a5da4a, 0xae1c326847bd4a133e5dee6b2ca67c, 0xe249]), + is_infinity: false + }; + + let actual = iso_map(p); + + let expected: Secp256k1 = BigCurve { + x: BigNum::from_array([0x7c2a947a20fd9ad71039f8b0e29ff8, 0x6d261a5e00fe5cf45e827b507643e6, 0xf89d]), + y: BigNum::from_array([0x1ce936d563bc1cee1dcffc806caf57, 0x55e0cc34a9176ead91c6c3acb1aacb, 0xb338]), + is_infinity: false + }; + + assert(actual == expected); } diff --git a/crates/plume/src/lib.nr b/crates/plume/src/lib.nr index 6b9d16f..8ac1ef7 100644 --- a/crates/plume/src/lib.nr +++ b/crates/plume/src/lib.nr @@ -1,82 +1,93 @@ -mod constants; -mod utils; mod hash_to_curve; mod hash_to_field; mod expand_message_xmd; mod map_to_curve; mod iso_map; -mod ec_ops; use std::hash::sha256; use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fr, Secp256k1Scalar}; +use noir_bigcurve::scalar_field::ScalarField; +use noir_bigcurve::BigCurve; -use crate::utils::rev_bytes_32; use crate::hash_to_curve::hash_to_curve; -use crate::constants::{ZERO, PLUME_MSG_LEN}; -use crate::ec_ops::{Point, point_mul, point_add}; -global G = ( - BigNum::from_array([0x9bfcdb2dce28d959f2815b16f81798, 0x667ef9dcbbac55a06295ce870b0702, 0x79be]), - BigNum::from_array([0x17b448a68554199c47d08ffb10d4b8, 0xda7726a3c4655da4fbfc0e1108a8fd, 0x483a]) -); +global G: Secp256k1 = BigCurve::one(); -fn a_div_b_pow_c(a: Point, b: Point, c: [u8; 32]) -> Point { - let b_pow_c = point_mul(c, b); - point_add(a, (b_pow_c.0, ZERO - b_pow_c.1)) -} +// r*G - r_point +// r*h - hashed_to_curve_r +// sha256(G || Pk || H || N || r*G || r*H) +pub fn plume_v1(msg: [u8; N], c: [u8; 32], s: Secp256k1Scalar, pk: Secp256k1, nullifier: Secp256k1) { + let (r_point, hashed_to_curve_r, hashed_to_curve) = check_ec_equations(msg, c, s, pk, nullifier); + let actual_c = sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r); -// Apply byte reverse -fn compress_ec_point(pk: Point) -> [u8; 33] { - let x: [u8; 32] = pk.0.to_le_bytes(); - let mut compressed = [0 as u8; 33]; + assert(actual_c == c); +} - let tmp: [u8; 32] = pk.1.to_le_bytes(); - compressed[0] = (tmp[0] & 1) + 2; +// https://www.notion.so/mantanetwork/PLUME-Discussion-6f4b7e7cf63e4e33976f6e697bf349ff +pub fn plume_v2(msg: [u8; N], c2: [u8; 32], s2: Secp256k1Scalar, pk: Secp256k1, nullifier: Secp256k1) { + let (r_point, hashed_to_curve_r, _) = check_ec_equations(msg, c2, s2, pk, nullifier); + let actual_c2 = sha256_6_coordinates(nullifier, r_point, hashed_to_curve_r); - for i in 0..32 { - compressed[32-i] = x[i]; - } - compressed + assert(actual_c2 == c2); } // Return values - r_point, hashed_to_curve_r, hashed_to_curve -fn check_ec_equations(msg: [u8; N], c: [u8; 32], s: [u8; 32], pk: Point, nullifier: Point) -> (Point, Point, Point) { - // ECDSAPrivToPub - let s_point = point_mul(s, G); +fn check_ec_equations( + msg: [u8; N], + c: [u8; 32], + s: Secp256k1Scalar, + pk: Secp256k1, + nullifier: Secp256k1 +) -> (Secp256k1, Secp256k1, Secp256k1) { + let c: Secp256k1Fr = BigNum::from_be_bytes(c); + let c: Secp256k1Scalar = ScalarField::from_bignum(c); + + let s_point = G.mul(s); let r_point = a_div_b_pow_c(s_point, pk, c); - let mut plume_msg = [0; PLUME_MSG_LEN]; - let pk_compress = compress_ec_point(pk); + let plume_msg = form_plume_msg(msg, pk); + let hashed_to_curve = hash_to_curve(plume_msg); + let h_pow_s = hashed_to_curve.mul(s); + let hashed_to_curve_r = a_div_b_pow_c(h_pow_s, nullifier, c); + + (r_point, hashed_to_curve_r, hashed_to_curve) +} + +fn a_div_b_pow_c(a: Secp256k1, b: Secp256k1, c: Secp256k1Scalar) -> Secp256k1 { + let b_pow_c = b.mul(c); + a + b_pow_c.neg() +} + +fn form_plume_msg(msg: [u8; N], pk: Secp256k1) -> [u8; N + 33] { + let mut plume_msg = [0; N + 33]; // 33 bytes for compressed pk + for i in 0..N { plume_msg[i] = msg[i]; } + + let compressed_pk = compress_ec_point(pk); for i in 0..33 { - plume_msg[N + i] = pk_compress[i]; + plume_msg[N + i] = compressed_pk[i]; } - let hashed_to_curve = hash_to_curve(plume_msg); - let h_pow_s = point_mul(s, hashed_to_curve); - let hashed_to_curve_r = a_div_b_pow_c(h_pow_s, nullifier, c); - (r_point, hashed_to_curve_r, hashed_to_curve) + plume_msg } -fn sha256_6_coordinates(nullifier: Point, gr: Point, hr: Point) -> [u8; 32] { - let mut compressed = [[0 as u8; 33]; 3]; - compressed[0] = compress_ec_point(nullifier); - compressed[1] = compress_ec_point(gr); - compressed[2] = compress_ec_point(hr); +fn compress_ec_point(pk: Secp256k1) -> [u8; 33] { + let x: [u8; 32] = pk.x.to_le_bytes(); + let mut compressed = [0 as u8; 33]; - // Concatenate all compressed bytes - let mut res = [0 as u8; 99]; - for i in 0..3 { - for j in 0..33 { - res[i*33 + j] = compressed[i][j]; - } + let tmp: [u8; 32] = pk.y.to_le_bytes(); + compressed[0] = (tmp[0] & 1) + 2; + + for i in 0..32 { + compressed[32-i] = x[i]; } - sha256(res) + compressed } -fn sha256_12_coordinates(pk: Point, h: Point, nullifier: Point, gr: Point, hr: Point) -> [u8; 32] { +fn sha256_12_coordinates(pk: Secp256k1, h: Secp256k1, nullifier: Secp256k1, gr: Secp256k1, hr: Secp256k1) -> [u8; 32] { let mut compressed = [[0 as u8; 33]; 6]; compressed[0] = compress_ec_point(G); compressed[1] = compress_ec_point(pk); @@ -85,7 +96,7 @@ fn sha256_12_coordinates(pk: Point, h: Point, nullifier: Point, gr: Point, hr: P compressed[4] = compress_ec_point(gr); compressed[5] = compress_ec_point(hr); - // Concatenate all compressed bytes + // Concatenate let mut res = [0 as u8; 198]; for i in 0..6 { for j in 0..33 { @@ -95,189 +106,279 @@ fn sha256_12_coordinates(pk: Point, h: Point, nullifier: Point, gr: Point, hr: P sha256(res) } -// r*G - r_point -// r*h - hashed_to_curve_r -// sha256(G || Pk || H || N || r*G || r*H) -pub fn plume_v1(msg: [u8; N], c: [u8; 32], s: [u8; 32], pk: Point, nullifier: Point) { - let (r_point, hashed_to_curve_r, hashed_to_curve) = check_ec_equations(msg, c, s, pk, nullifier); - let actual_c = rev_bytes_32(sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r)); - assert(actual_c == c); -} +fn sha256_6_coordinates(nullifier: Secp256k1, gr: Secp256k1, hr: Secp256k1) -> [u8; 32] { + let mut compressed = [[0 as u8; 33]; 3]; + compressed[0] = compress_ec_point(nullifier); + compressed[1] = compress_ec_point(gr); + compressed[2] = compress_ec_point(hr); -// https://www.notion.so/mantanetwork/PLUME-Discussion-6f4b7e7cf63e4e33976f6e697bf349ff -pub fn plume_v2(msg: [u8; N], c2: [u8; 32], s2: [u8; 32], pk: Point, nullifier: Point) { - let (r_point, hashed_to_curve_r, _) = check_ec_equations(msg, c2, s2, pk, nullifier); - let actual_c2 = rev_bytes_32(sha256_6_coordinates(nullifier, r_point, hashed_to_curve_r)); - assert(actual_c2 == c2); + // Concatenate + let mut res = [0 as u8; 99]; + for i in 0..3 { + for j in 0..33 { + res[i*33 + j] = compressed[i][j]; + } + } + sha256(res) } #[test] fn test_compress_ec_point() { - let sk = [ - 112, 243, 161, 202, 0, 115, 239, 202, 31, 179, 58, 65, 45, 143, 230, 117, 69, 15, 193, 56, 3, 81, 140, 224, 217, 195, 210, 108, 178, 7, 102, 141 - ]; - let pk = point_mul(sk, G); + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 141, 102, 7, 178, 108, 210, 195, 217, 224, 140, 81, 3, 56, 193, 15, 69, 117, 230, 143, 45, 65, 58, 179, 31, 202, 239, 115, 0, 202, 161, 243, 112 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + let pk = G.mul(sk); - let compressed_pk = compress_ec_point(pk); - let expected_compressed_pk = [ + let actual = compress_ec_point(pk); + + let expected = [ 2, 251, 188, 92, 195, 140, 107, 160, 47, 132, 242, 112, 141, 138, 178, 59, 234, 158, 144, 47, 203, 20, 59, 174, 56, 127, 68, 229, 111, 95, 233, 172, 226 ]; - assert(compressed_pk == expected_compressed_pk); + + assert(actual == expected); } #[test] fn test_nullifier() { - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - let H = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] ); - - let nullifier = point_mul(sk, H); - let expected_nullifier = ([ - 48, 88, 229, 103, 12, 29, 111, 98, 30, 92, 164, 115, 100, 166, 197, 252, 69, 231, 204, 194, 224, 185, 228, 221, 138, 239, 114, 129, 210, 62, 188, 87 - ], [ - 115, 203, 158, 229, 127, 8, 214, 145, 168, 143, 163, 126, 230, 58, 159, 159, 96, 17, 225, 136, 33, 221, 110, 228, 58, 243, 88, 141, 72, 65, 47, 106 - ]); - assert((nullifier.0.to_le_bytes(), nullifier.1.to_le_bytes()) == expected_nullifier); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + + let H: Secp256k1 = BigCurve { + x: BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), + y: BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]), + is_infinity: false + }; + + let actual = H.mul(sk); + + let expected: Secp256k1 = BigCurve { + x: BigNum::from_be_bytes( + [ + 87, 188, 62, 210, 129, 114, 239, 138, 221, 228, 185, 224, 194, 204, 231, 69, 252, 197, 166, 100, 115, 164, 92, 30, 98, 111, 29, 12, 103, 229, 88, 48 + ] + ), + y: BigNum::from_be_bytes( + [ + 106, 47, 65, 72, 141, 88, 243, 58, 228, 110, 221, 33, 136, 225, 17, 96, 159, 159, 58, 230, 126, 163, 143, 168, 145, 214, 8, 127, 229, 158, 203, 115 + ] + ), + is_infinity: false + }; + + assert(actual == expected); } #[test] fn test_r_point() { - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - let s = [ - 202, 40, 186, 121, 96, 189, 224, 125, 45, 19, 234, 232, 99, 209, 144, 177, 95, 151, 46, 209, 51, 227, 97, 247, 229, 111, 203, 132, 125, 2, 159, 230 - ]; - let c = [ - 84, 50, 232, 188, 237, 50, 59, 254, 35, 82, 174, 186, 20, 85, 170, 45, 111, 86, 182, 159, 71, 26, 115, 32, 175, 219, 109, 146, 44, 252, 167, 198 - ]; - let pk = point_mul(sk, G); - let s_point = point_mul(s, G); - let r_point = a_div_b_pow_c(s_point, pk, c); + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + + let s: Secp256k1Fr = BigNum::from_be_bytes( + [ + 230, 159, 2, 125, 132, 203, 111, 229, 247, 97, 227, 51, 209, 46, 151, 95, 177, 144, 209, 99, 232, 234, 19, 45, 125, 224, 189, 96, 121, 186, 40, 202 + ] + ); + let s: Secp256k1Scalar = ScalarField::from_bignum(s); - let expected_r_point = ([ - 4, 152, 254, 54, 199, 45, 14, 89, 41, 132, 162, 98, 41, 102, 118, 128, 129, 101, 19, 40, 42, 109, 188, 122, 210, 42, 126, 14, 53, 164, 140, 157 - ], [ - 161, 197, 112, 118, 106, 129, 84, 144, 155, 45, 71, 18, 81, 228, 235, 188, 198, 170, 195, 217, 53, 200, 35, 70, 133, 78, 253, 138, 11, 195, 8, 255 - ]); - assert((r_point.0.to_le_bytes(), r_point.1.to_le_bytes()) == expected_r_point); + let c: Secp256k1Fr = BigNum::from_be_bytes( + [ + 198, 167, 252, 44, 146, 109, 219, 175, 32, 115, 26, 71, 159, 182, 86, 111, 45, 170, 85, 20, 186, 174, 82, 35, 254, 59, 50, 237, 188, 232, 50, 84 + ] + ); + let c: Secp256k1Scalar = ScalarField::from_bignum(c); + + let pk = G.mul(sk); + let s_point = G.mul(s); + + let actual = a_div_b_pow_c(s_point, pk, c); + + let expected: Secp256k1 = BigCurve { + x: BigNum::from_be_bytes( + [ + 157, 140, 164, 53, 14, 126, 42, 210, 122, 188, 109, 42, 40, 19, 101, 129, 128, 118, 102, 41, 98, 162, 132, 41, 89, 14, 45, 199, 54, 254, 152, 4 + ] + ), + y: BigNum::from_be_bytes( + [ + 255, 8, 195, 11, 138, 253, 78, 133, 70, 35, 200, 53, 217, 195, 170, 198, 188, 235, 228, 81, 18, 71, 45, 155, 144, 84, 129, 106, 118, 112, 197, 161 + ] + ), + is_infinity: false + }; + + assert(actual == expected); } -// Failed if the MSG_LEN constant has a value other than 29 -/* #[test] -fn test_hashed_to_curve_msg_with_pk() { - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - let pk = point_mul(sk, G); +fn test_hashed_to_curve_plume_msg() { + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + let pk = G.mul(sk); let msg = [ 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 ]; - let mut plume_msg = [0 as u8; PLUME_MSG_LEN]; - let pk_compress = compress_ec_point(pk); - for i in 0..msg.len() { - plume_msg[i] = msg[i]; - } - for i in 0..33 { - plume_msg[msg.len() + i] = pk_compress[i]; - } - let (x, y) = hash_to_curve(plume_msg); - - let expected_H = ([ - 101, 11, 128, 176, 13, 25, 162, 54, 17, 77, 197, 73, 188, 255, 42, 31, 192, 205, 171, 149, 147, 136, 24, 194, 35, 159, 103, 18, 14, 45, 172, 188 - ], [ - 110, 150, 112, 205, 240, 135, 93, 20, 82, 55, 43, 227, 83, 26, 169, 176, 35, 161, 144, 31, 8, 72, 211, 87, 231, 192, 116, 201, 57, 179, 207, 59 - ]); - assert((x.to_le_bytes(), y.to_le_bytes()) == expected_H); + let plume_msg = form_plume_msg(msg, pk); + + let actual = hash_to_curve(plume_msg); + + let expected: Secp256k1 = BigCurve { + x: BigNum::from_be_bytes( + [ + 188, 172, 45, 14, 18, 103, 159, 35, 194, 24, 136, 147, 149, 171, 205, 192, 31, 42, 255, 188, 73, 197, 77, 17, 54, 162, 25, 13, 176, 128, 11, 101 + ] + ), + y: BigNum::from_be_bytes( + [ + 59, 207, 179, 57, 201, 116, 192, 231, 87, 211, 72, 8, 31, 144, 161, 35, 176, 169, 26, 83, 227, 43, 55, 82, 20, 93, 135, 240, 205, 112, 150, 110 + ] + ), + is_infinity: false + }; + + assert(actual == expected); } -*/ -// Too slow. Stopped in CI -/* #[test] fn test_hashed_to_curve_r() { - let s = [ - 202, 40, 186, 121, 96, 189, 224, 125, 45, 19, 234, 232, 99, 209, 144, 177, 95, 151, 46, 209, 51, 227, 97, 247, 229, 111, 203, 132, 125, 2, 159, 230 - ]; - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - let H = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) + let s: Secp256k1Fr = BigNum::from_be_bytes( + [ + 230, 159, 2, 125, 132, 203, 111, 229, 247, 97, 227, 51, 209, 46, 151, 95, 177, 144, 209, 99, 232, 234, 19, 45, 125, 224, 189, 96, 121, 186, 40, 202 + ] ); - let c = [ - 84, 50, 232, 188, 237, 50, 59, 254, 35, 82, 174, 186, 20, 85, 170, 45, 111, 86, 182, 159, 71, 26, 115, 32, 175, 219, 109, 146, 44, 252, 167, 198 - ]; + let s: Secp256k1Scalar = ScalarField::from_bignum(s); - let nullifier = point_mul(sk, H); - let h_pow_s = point_mul(s, H); - let (x, y) = a_div_b_pow_c(h_pow_s, nullifier, c); + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); - let expected_hashed_to_curve_r = ([ - 124, 185, 39, 205, 252, 88, 5, 39, 219, 49, 33, 21, 77, 159, 87, 105, 40, 125, 226, 84, 166, 233, 177, 165, 167, 159, 197, 99, 111, 124, 1, 109 - ], [ - 237, 86, 172, 119, 183, 144, 226, 164, 161, 245, 202, 198, 211, 68, 63, 62, 248, 101, 138, 168, 128, 143, 74, 86, 140, 129, 153, 92, 251, 67, 108, 88 - ]); - assert((x.to_le_bytes(), y.to_le_bytes()) == expected_hashed_to_curve_r); + let H: Secp256k1 = BigCurve { + x: BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), + y: BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]), + is_infinity: false + }; + + let c: Secp256k1Fr = BigNum::from_be_bytes( + [ + 198, 167, 252, 44, 146, 109, 219, 175, 32, 115, 26, 71, 159, 182, 86, 111, 45, 170, 85, 20, 186, 174, 82, 35, 254, 59, 50, 237, 188, 232, 50, 84 + ] + ); + let c: Secp256k1Scalar = ScalarField::from_bignum(c); + + let nullifier = H.mul(sk); + let h_pow_s = H.mul(s); + + let actual = a_div_b_pow_c(h_pow_s, nullifier, c); + + let expected : Secp256k1 = BigCurve { + x: BigNum::from_be_bytes( + [ + 109, 1, 124, 111, 99, 197, 159, 167, 165, 177, 233, 166, 84, 226, 125, 40, 105, 87, 159, 77, 21, 33, 49, 219, 39, 5, 88, 252, 205, 39, 185, 124 + ] + ), + y: BigNum::from_be_bytes( + [ + 88, 108, 67, 251, 92, 153, 129, 140, 86, 74, 143, 128, 168, 138, 101, 248, 62, 63, 68, 211, 198, 202, 245, 161, 164, 226, 144, 183, 119, 172, 86, 237 + ] + ), + is_infinity: false + }; + + assert(actual == expected); } #[test] fn test_sha_256_12_coordinates() { - let hashed_to_curve = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) - ); - let r_point = ( - BigNum::from_array([0x76662962a28429590e2dc736fe9804, 0xa4350e7e2ad27abc6d2a2813658180, 0x9d8c]), BigNum::from_array([0xebe45112472d9b9054816a7670c5a1, 0xc30b8afd4e854623c835d9c3aac6bc, 0xff08]) - ); - let hashed_to_curve_r = ( - BigNum::from_array([0x579f4d152131db270558fccd27b97c, 0x7c6f63c59fa7a5b1e9a654e27d2869, 0x6d01]), BigNum::from_array([0x3f44d3c6caf5a1a4e290b777ac56ed, 0x43fb5c99818c564a8f80a88a65f83e, 0x586c]) - ); - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 - ]; - let pk = point_mul(sk, G); - let nullifier = point_mul(sk, hashed_to_curve); - - let actual_c = sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r); - let expected_c = rev_bytes_32( + let hashed_to_curve: Secp256k1 = BigCurve { + x: BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), + y: BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]), + is_infinity: false + }; + + let r_point: Secp256k1 = BigCurve { + x: BigNum::from_array([0x76662962a28429590e2dc736fe9804, 0xa4350e7e2ad27abc6d2a2813658180, 0x9d8c]), + y: BigNum::from_array([0xebe45112472d9b9054816a7670c5a1, 0xc30b8afd4e854623c835d9c3aac6bc, 0xff08]), + is_infinity: false + }; + + let hashed_to_curve_r: Secp256k1 = BigCurve { + x: BigNum::from_array([0x579f4d152131db270558fccd27b97c, 0x7c6f63c59fa7a5b1e9a654e27d2869, 0x6d01]), + y: BigNum::from_array([0x3f44d3c6caf5a1a4e290b777ac56ed, 0x43fb5c99818c564a8f80a88a65f83e, 0x586c]), + is_infinity: false + }; + + let sk: Secp256k1Fr = BigNum::from_be_bytes( [ - 84, 50, 232, 188, 237, 50, 59, 254, 35, 82, 174, 186, 20, 85, 170, 45, 111, 86, 182, 159, 71, 26, 115, 32, 175, 219, 109, 146, 44, 252, 167, 198 + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 ] ); - assert(actual_c == expected_c); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + + let pk = G.mul(sk); + let nullifier = hashed_to_curve.mul(sk); + + let actual = sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r); + + let expected = [ + 198, 167, 252, 44, 146, 109, 219, 175, 32, 115, 26, 71, 159, 182, 86, 111, 45, 170, 85, 20, 186, 174, 82, 35, 254, 59, 50, 237, 188, 232, 50, 84 + ]; + + assert(actual == expected); } -*/ -// Failed if the MSG_LEN constant has a value other than 29 -/* #[test] fn test_plume_v1() { - // "An example app message string", 29 len let msg = [ 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 ]; - let H = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) - ); - let s = [ - 202, 40, 186, 121, 96, 189, 224, 125, 45, 19, 234, 232, 99, 209, 144, 177, 95, 151, 46, 209, 51, 227, 97, 247, 229, 111, 203, 132, 125, 2, 159, 230 - ]; let c = [ - 84, 50, 232, 188, 237, 50, 59, 254, 35, 82, 174, 186, 20, 85, 170, 45, 111, 86, 182, 159, 71, 26, 115, 32, 175, 219, 109, 146, 44, 252, 167, 198 - ]; - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 + 198, 167, 252, 44, 146, 109, 219, 175, 32, 115, 26, 71, 159, 182, 86, 111, 45, 170, 85, 20, 186, 174, 82, 35, 254, 59, 50, 237, 188, 232, 50, 84 ]; - let pk = point_mul(sk, G); - let nullifier = point_mul(sk, H); - plume_v1(msg, c, s, pk, nullifier); // assert inside function + let s: Secp256k1Fr = BigNum::from_be_bytes( + [ + 230, 159, 2, 125, 132, 203, 111, 229, 247, 97, 227, 51, 209, 46, 151, 95, 177, 144, 209, 99, 232, 234, 19, 45, 125, 224, 189, 96, 121, 186, 40, 202 + ] + ); + let s: Secp256k1Scalar = ScalarField::from_bignum(s); + + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + + let pk = G.mul(sk); + + let H: Secp256k1 = BigCurve { + x: BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), + y: BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]), + is_infinity: false + }; + + let nullifier = H.mul(sk); + + plume_v1(msg, c, s, pk, nullifier); // assert inside the function } #[test] @@ -285,22 +386,33 @@ fn test_plume_v2() { let msg = [ 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 ]; - let H = ( - BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]) - ); - let s2 = [ - 107, 19, 152, 128, 203, 119, 17, 15, 146, 90, 8, 17, 214, 75, 82, 146, 122, 148, 178, 115, 26, 123, 121, 0, 34, 248, 82, 100, 187, 143, 142, 82 - ]; - let c2 = [ - 150, 235, 52, 52, 54, 59, 107, 138, 158, 11, 171, 131, 167, 211, 91, 71, 75, 231, 149, 12, 114, 112, 74, 244, 212, 16, 80, 112, 23, 183, 191, 61 - ]; - let sk = [ - 100, 180, 114, 218, 109, 165, 84, 202, 172, 62, 78, 11, 19, 200, 68, 91, 26, 119, 244, 89, 238, 168, 79, 31, 88, 139, 95, 113, 61, 66, 155, 81 + 61, 191, 183, 23, 112, 80, 16, 212, 244, 74, 112, 114, 12, 149, 231, 75, 71, 91, 211, 167, 131, 171, 11, 158, 138, 107, 59, 54, 52, 52, 235, 150 ]; - let pk = point_mul(sk, G); - let nullifier = point_mul(sk, H); - plume_v2(msg, c2, s2, pk, nullifier); // assert inside function + let s2: Secp256k1Fr = BigNum::from_be_bytes( + [ + 82, 142, 143, 187, 100, 82, 248, 34, 0, 121, 123, 26, 115, 178, 148, 122, 146, 82, 75, 214, 17, 8, 90, 146, 15, 17, 119, 203, 128, 152, 19, 107 + ] + ); + let s2: Secp256k1Scalar = ScalarField::from_bignum(s2); + + let sk: Secp256k1Fr = BigNum::from_be_bytes( + [ + 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100 + ] + ); + let sk: Secp256k1Scalar = ScalarField::from_bignum(sk); + + let pk = G.mul(sk); + + let H: Secp256k1 = BigCurve { + x: BigNum::from_array([0x2affbc49c54d1136a2190db0800b65, 0x2d0e12679f23c218889395abcdc01f, 0xbcac]), + y: BigNum::from_array([0xa91a53e32b3752145d87f0cd70966e, 0xb339c974c0e757d348081f90a123b0, 0x3bcf]), + is_infinity: false + }; + + let nullifier = H.mul(sk); + + plume_v2(msg, c2, s2, pk, nullifier); // assert inside the function } -*/ diff --git a/crates/plume/src/map_to_curve.nr b/crates/plume/src/map_to_curve.nr index f7d82f7..29ea403 100644 --- a/crates/plume/src/map_to_curve.nr +++ b/crates/plume/src/map_to_curve.nr @@ -1,99 +1,133 @@ -use bignum::BigNum; -use crate::constants::{Fq, ZERO}; -use crate::ec_ops::Point; -use crate::utils::mod_sqrt; - -// Constants are taken from the .circom code, converted to a little endian bytes array -// https://github.com/geometryxyz/secp256k1_hash_to_curve/blob/main/circuits/circom/constants.circom -fn get_z() -> [Field; 3] { - [0xfffffffffffffffffffffefffffc24, 0xffffffffffffffffffffffffffffff, 0xffff] -} - -fn get_a() -> [Field; 3] { - [0x53d363cb6f0e5d405447c01a444533, 0x31abdd661adca08a5558f0f5d272e9, 0x3f87] -} +/* + Simplified SWU (Shallue-van de Woestijne-Ulas) method for secp256k1. + + See the link below for more details: -fn get_b() -> [Field; 3] { - [0x6eb, 0, 0] -} - -fn xy2_selector(x1: Fq, x2: Fq, gx1: Fq, gx2: Fq) -> Point { - let gx1_sqrt = mod_sqrt(gx1); - let gx2_sqrt = mod_sqrt(gx2); + https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-simplified-shallue-van-de-w +*/ - let s1 = gx1_sqrt * gx1_sqrt == gx1; - let s2 = gx2_sqrt * gx2_sqrt == gx2; - assert(s1 ^ s2); - - if s1 { (x1, gx1_sqrt) } else { (x2, gx2_sqrt) } -} +use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fq, Secp256k1_Params}; +use noir_bigcurve::BigCurve; -// As a result, we get a point not on the Secp256k1 curve, but a point E' that isogeny to this curve -// Formula from https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-simplified-shallue-van-de-w -pub fn map_to_curve(u: Fq) -> Point { - let z = BigNum::from_array(get_z()); +// Returns point E' isogeneous to secp256k1. +pub fn map_to_curve(u: Secp256k1Fq) -> Secp256k1 { + let a = a(); + let b = b(); + let z = z(); + let one: Secp256k1Fq = BigNum::one(); - let tv1 = BigNum::one() / (z * z * u * u * u * u + z * u * u); - let a = BigNum::from_array(get_a()); - let b = BigNum::from_array(get_b()); - let x1 = ((ZERO - b) / a) * (BigNum::one() + tv1); + let tv1 = one / (z * z * u * u * u * u + z * u * u); + let x1 = (b.neg() / a) * (one + tv1); let gx1 = x1 * x1 * x1 + a * x1 + b; let x2 = z * u * u * x1; let gx2 = x2 * x2 * x2 + a * x2 + b; - let (x, y) = xy2_selector(x1, x2, gx1, gx2); + let (x, mut y) = select_xy(x1, x2, gx1, gx2); let ubyte: [u8; 32] = u.to_le_bytes(); let ybyte: [u8; 32] = y.to_le_bytes(); - let left: [u1; 8] = (ubyte[0] as Field).to_le_bits(); - let right: [u1; 8] = (ybyte[0] as Field).to_le_bits(); + let u_sign: u1 = (ubyte[0] as Field).to_le_bits::<8>()[0]; + let y_sign: u1 = (ybyte[0] as Field).to_le_bits::<8>()[0]; + + if u_sign != y_sign { + y = y.neg(); + } + + BigCurve { x, y, is_infinity: false } +} + +fn select_xy( + x1: Secp256k1Fq, + x2: Secp256k1Fq, + gx1: Secp256k1Fq, + gx2: Secp256k1Fq +) -> (Secp256k1Fq, Secp256k1Fq) { + let gx1_sqrt = unsafe { + gx1.__tonelli_shanks_sqrt() + }; + let gx2_sqrt = unsafe { + gx2.__tonelli_shanks_sqrt() + }; + + let gx1_is_square = gx1_sqrt.is_some(); + + let x: Secp256k1Fq = if gx1_is_square { x1 } else { x2 }; + let y = gx1_sqrt.xor(gx2_sqrt).unwrap(); + + let y_preimage: Secp256k1Fq = if gx1_is_square { gx1 } else { gx2 }; + + // Constrain out-of-circuit root computation. + let y_squared = y * y; + assert(y_preimage == y_squared, "Square root is incorrect"); - let y = if left[0] == right[0] { y } else { ZERO - y }; (x, y) } + +// ****************** CONSTANTS ****************** // +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-8.7 + +fn z() -> Secp256k1Fq { + BigNum::from_array([0xfffffffffffffffffffffefffffc24, 0xffffffffffffffffffffffffffffff, 0xffff]) +} + +// Weierstrass equation `a` parameter for curve E' isogeneous to secp256k1. +fn a() -> Secp256k1Fq { + BigNum::from_array([0x53d363cb6f0e5d405447c01a444533, 0x31abdd661adca08a5558f0f5d272e9, 0x3f87]) +} + +// Weierstrass equation `b` parameter for curve E' isogeneous to secp256k1. +fn b() -> Secp256k1Fq { + BigNum::from_array([0x6eb, 0, 0]) +} + #[test] -fn test_mod_mul_inv_x1() { - let x1: Fq = BigNum::from_array([0x387936733e29cddb43759809208354, 0xc334daf72303fb27f6aad8201a9465, 0xc6f1]); +fn test_inverse() { + let value: Secp256k1Fq = BigNum::from_array([0x387936733e29cddb43759809208354, 0xc334daf72303fb27f6aad8201a9465, 0xc6f1]); + + let actual = BigNum::one() / value; - let inv_x1 = BigNum::one() / x1; - let expected_inv_x1: [u8; 32] = [ + let expected: [u8; 32] = [ 211, 142, 221, 78, 176, 90, 13, 18, 140, 253, 186, 38, 111, 230, 156, 220, 55, 89, 204, 218, 31, 162, 175, 33, 15, 146, 219, 86, 70, 80, 101, 19 ]; - assert(inv_x1.to_le_bytes() == expected_inv_x1); + + assert(actual.to_le_bytes() == expected); } #[test] -fn test_xy2_selector_1() { - let x1 = BigNum::from_array([123, 0, 0]); - let x2 = BigNum::from_array([200, 0, 0]); - let gx1 = BigNum::from_array([4, 0, 0]); - let gx2 = BigNum::from_array([5, 0, 0]); +fn test_select_xy_1() { + let x1: Secp256k1Fq = BigNum::from_array([123, 0, 0]); + let x2: Secp256k1Fq = BigNum::from_array([200, 0, 0]); + let gx1: Secp256k1Fq = BigNum::from_array([4, 0, 0]); + let gx2: Secp256k1Fq = BigNum::from_array([5, 0, 0]); + + let (actual_x, actual_y) = select_xy(x1, x2, gx1, gx2); - let (actual_x, actual_gx) = xy2_selector(x1, x2, gx1, gx2); assert(actual_x == x1); - assert(actual_gx == BigNum::from_array([2, 0, 0])); + assert(actual_y == BigNum::from_array([2, 0, 0])); } #[test] -fn test_xy2_selector_2() { - let x1 = BigNum::from_array([123, 0, 0]); - let x2 = BigNum::from_array([200, 1, 0]); - let gx1 = BigNum::from_array([5, 0, 0]); - let gx2 = BigNum::from_array([4, 0, 0]); +fn test_select_xy_2() { + let x1: Secp256k1Fq = BigNum::from_array([123, 0, 0]); + let x2: Secp256k1Fq = BigNum::from_array([200, 1, 0]); + let gx1: Secp256k1Fq = BigNum::from_array([5, 0, 0]); + let gx2: Secp256k1Fq = BigNum::from_array([4, 0, 0]); + + let (actual_x, actual_y) = select_xy(x1, x2, gx1, gx2); - let (actual_x, actual_gx) = xy2_selector(x1, x2, gx1, gx2); assert(actual_x == x2); - assert(actual_gx == BigNum::from_array([2, 0, 0])); + assert(actual_y == BigNum::from_array([2, 0, 0])); } #[test] fn test_map_to_curve() { - let u0_bytes = BigNum::from_array([0x491f544767e18a4873f397b08a2b61, 0xab5d3679a1f7601e3bdf94ced1f43e, 0x128a]); + let u = BigNum::from_array([0x491f544767e18a4873f397b08a2b61, 0xab5d3679a1f7601e3bdf94ced1f43e, 0x128a]); - let (x, y) = map_to_curve(u0_bytes); + let actual_p= map_to_curve(u); let expected_x = [ 181, 145, 157, 194, 47, 137, 194, 182, @@ -108,6 +142,6 @@ fn test_map_to_curve() { 236, 154, 191, 129, 133, 161, 34, 59 ]; - assert(x.to_le_bytes() == expected_x); - assert(y.to_le_bytes() == expected_y); + assert(actual_p.x.to_le_bytes() == expected_x); + assert(actual_p.y.to_le_bytes() == expected_y); } diff --git a/crates/plume/src/utils.nr b/crates/plume/src/utils.nr deleted file mode 100644 index ae14033..0000000 --- a/crates/plume/src/utils.nr +++ /dev/null @@ -1,35 +0,0 @@ -use bignum::BigNum; -use crate::constants::Fq; - -pub fn rev_bytes_32(mut bytes: [u8; 32]) -> [u8; 32] { - for i in 0..16 { - let temp = bytes[i]; - bytes[i] = bytes[31-i]; - bytes[31-i] = temp; - } - bytes -} - -// Binary power algorithm https://cp-algorithms.com/algebra/binary-exp.html -pub fn bin_pow(mut num: Fq, exp: [u8; 32]) -> Fq { - let mut res = BigNum::one(); - - for i in 0..exp.len() { - for j in 0..8 { - if exp[i] & (1 << j) != 0 { - res = res * num; - } - num = num * num; - } - } - res -} - -// We use the formula R = num^((p+1)/4), since SECP256K1_PRIME % 4 == 3 -// https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm -// secp256k1_prime is 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 constant -pub fn mod_sqrt(num: Fq) -> Fq { - let secp256k1_prime_plus_one: Fq = BigNum::from_array([0xfffffffffffffffffffffefffffc30, 0xffffffffffffffffffffffffffffff, 0xffff]); - let exp: [u8; 32] = (secp256k1_prime_plus_one / BigNum::from_array([4, 0, 0])).to_le_bytes(); - bin_pow(num, exp) -} diff --git a/crates/use/Nargo.toml b/crates/use/Nargo.toml index 9ec3bfb..ba070d5 100644 --- a/crates/use/Nargo.toml +++ b/crates/use/Nargo.toml @@ -8,4 +8,5 @@ compiler_version = ">=0.35.0" [dependencies] plume = { path = "../plume" } -bignum = {tag = "v0.3.6", git = "https://github.com/noir-lang/noir-bignum"} \ No newline at end of file +bignum = {tag = "v0.3.7", git = "https://github.com/noir-lang/noir-bignum"} +noir_bigcurve = {tag = "v0.4", git = "https://github.com/noir-lang/noir_bigcurve"} \ No newline at end of file diff --git a/crates/use/Prover.toml b/crates/use/Prover.toml index 5c19dd4..a6a523e 100644 --- a/crates/use/Prover.toml +++ b/crates/use/Prover.toml @@ -1,5 +1,5 @@ -c = ["35", "213", "240", "230", "83", "106", "211", "42", "233", "59", "126", "249", "183", "94", "47", "144", "13", "142", "146", "158", "185", "7", "214", "169", "80", "149", "226", "210", "63", "136", "218", "4"] -msg = ["17", "247", "111", "61", "124", "232", "169", "224", "114", "167", "101", "63", "77", "227", "157", "45", "52", "200", "247", "68", "49", "183", "234", "251", "234", "197", "192", "192", "240", "108", "233", "140"] -nullifier = [["219", "115", "2", "106", "76", "64", "175", "109", "32", "148", "84", "74", "22", "245", "25", "71", "76", "36", "204", "208", "16", "68", "117", "62", "171", "53", "155", "17", "102", "85", "210", "164"], ["216", "28", "64", "125", "12", "154", "192", "249", "180", "117", "222", "84", "193", "178", "240", "23", "210", "233", "16", "196", "239", "7", "180", "66", "205", "68", "47", "217", "185", "54", "6", "232"]] -pk = [["238", "72", "167", "119", "172", "97", "48", "202", "83", "47", "179", "139", "243", "117", "29", "102", "101", "9", "80", "45", "155", "99", "165", "233", "216", "248", "58", "177", "218", "10", "29", "158"], ["93", "3", "208", "168", "244", "122", "46", "224", "148", "45", "219", "25", "118", "225", "185", "170", "59", "108", "150", "34", "188", "109", "14", "247", "70", "229", "225", "121", "155", "245", "131", "121"]] -s = ["24", "151", "137", "225", "68", "60", "54", "21", "118", "30", "181", "115", "93", "114", "138", "193", "112", "33", "163", "18", "206", "207", "254", "234", "67", "125", "161", "181", "122", "206", "26", "54"] +c = ["53", "56", "241", "116", "247", "113", "134", "213", "193", "65", "151", "45", "21", "170", "18", "59", "83", "109", "226", "121", "204", "173", "236", "64", "86", "232", "242", "15", "37", "79", "226", "74"] +msg = ["74", "223", "32", "97", "177", "144", "197", "10", "58", "198", "201", "30", "96", "107", "23", "69", "13", "126", "108", "203", "33", "201", "101", "66", "77", "36", "65", "227", "36", "83", "187", "226"] +nullifier = [["88", "233", "237", "83", "167", "202", "118", "205", "248", "169", "110", "84", "82", "60", "243", "41", "186", "189", "121", "112", "11", "164", "13", "111", "47", "243", "131", "251", "46", "224", "116", "137"], ["213", "22", "193", "70", "149", "43", "149", "112", "12", "166", "64", "241", "242", "212", "208", "68", "219", "81", "135", "45", "243", "219", "210", "228", "72", "201", "68", "69", "29", "170", "234", "62"]] +pk = [["122", "186", "229", "218", "55", "150", "127", "92", "250", "27", "108", "44", "82", "215", "6", "183", "221", "50", "219", "205", "186", "5", "163", "196", "63", "106", "19", "156", "154", "244", "11", "59"], ["92", "161", "30", "116", "247", "146", "29", "73", "133", "16", "205", "120", "8", "179", "162", "43", "147", "97", "7", "224", "250", "135", "172", "135", "197", "131", "205", "59", "32", "113", "80", "126"]] +s = ["40", "27", "33", "89", "224", "169", "181", "143", "183", "9", "88", "211", "137", "93", "74", "178", "220", "18", "255", "20", "38", "254", "62", "187", "116", "253", "98", "243", "232", "163", "208", "23"] diff --git a/crates/use/src/main.nr b/crates/use/src/main.nr index 9c601cb..8edbfa8 100644 --- a/crates/use/src/main.nr +++ b/crates/use/src/main.nr @@ -1,10 +1,28 @@ use bignum::BigNum; -use plume::constants::MSG_LEN; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fr, Secp256k1Scalar}; +use noir_bigcurve::BigCurve; +use noir_bigcurve::scalar_field::ScalarField; + use plume::{plume_v1, plume_v2}; +global MSG_LEN: u32 = 32; + pub fn main(msg: [u8; MSG_LEN], c: [u8; 32], s: [u8; 32], pk: [[u8; 32]; 2], nullifier: [[u8; 32]; 2]) { - let pk = (BigNum::from_be_bytes(pk[0]), BigNum::from_be_bytes(pk[1])); - let nullifier = (BigNum::from_be_bytes(nullifier[0]), BigNum::from_be_bytes(nullifier[1])); + let s: Secp256k1Fr = BigNum::from_be_bytes(s); + let s: Secp256k1Scalar = ScalarField::from_bignum(s); + + let pk: Secp256k1 = BigCurve { + x: BigNum::from_be_bytes(pk[0]), + y: BigNum::from_be_bytes(pk[1]), + is_infinity: false // we never pass inf in Prover.toml + }; + + let nullifier: Secp256k1 = BigCurve { + x: BigNum::from_be_bytes(nullifier[0]), + y: BigNum::from_be_bytes(nullifier[1]), + is_infinity: false // we never pass inf in Prover.toml + }; + // Choose your plume variant and comment the other // plume_v1(msg, c, s, pk, nullifier); diff --git a/etc/gen.sage b/etc/gen.sage index 9edb050..51bdca0 100644 --- a/etc/gen.sage +++ b/etc/gen.sage @@ -40,9 +40,14 @@ def plume_generate_test_case(version1: bool, msg_len: int): c.reverse() s = (r + sk * bytes_to_num(c)) % SECP256K1_NUMBERS + s = num_to_bytes(int(s)) + c.reverse() + s.reverse() + Pk = point_to_be_bytes(Pk) N = point_to_be_bytes(N) - return (msg, c, num_to_bytes(int(s)), Pk, N) + + return (msg, c, s, Pk, N) def point_to_be_bytes(p): return (num_to_bytes(int(p[0]))[::-1], num_to_bytes(int(p[1]))[::-1]) diff --git a/etc/main.sage b/etc/main.sage index ec8f217..3d82774 100644 --- a/etc/main.sage +++ b/etc/main.sage @@ -46,8 +46,8 @@ def update_prover_toml(filepath, version1: bool, msg_len: int): def update_plume_version(is_v1: bool): path = "../crates/use/src/" # start from line 0 - p1_line = 9 - p2_line = 10 + p1_line = 27 + p2_line = 28 with open(path + 'main.nr', 'r') as file: lines = file.readlines() @@ -64,14 +64,14 @@ def update_plume_version(is_v1: bool): def update_MSG_LEN_variable(msg_len: int): - path = "../crates/plume/src/" - with open(path + 'constants.nr', 'r') as file: + path = "../crates/use/src/" + with open(path + 'main.nr', 'r') as file: lines = file.readlines() - MSG_LEN_line = 5 + MSG_LEN_line = 7 lines[MSG_LEN_line] = f"global MSG_LEN: u32 = {msg_len};\n" - with open(path + 'constants.nr', 'w') as file: + with open(path + 'main.nr', 'w') as file: file.writelines(lines) From 337f63d00d52f7394eb032058afebb12dd2f4d83 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Mon, 28 Oct 2024 14:50:51 +0200 Subject: [PATCH 02/10] ci: pin noir version --- .github/workflows/noir.yml | 52 +++++++++++++------------------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/.github/workflows/noir.yml b/.github/workflows/noir.yml index 2cc3667..880ab49 100644 --- a/.github/workflows/noir.yml +++ b/.github/workflows/noir.yml @@ -1,4 +1,4 @@ -name: noir +name: Noir CI on: pull_request: @@ -11,47 +11,29 @@ permissions: contents: read jobs: - fmt-noir: + noir: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v4 - - - name: Install Nargo - uses: noir-lang/noirup@v0.1.3 - with: - toolchain: nightly + + - name: Create `.nargo/bin` directory + shell: bash + run: | + mkdir -p $HOME/.nargo/bin + echo "${HOME}/.nargo/bin" >> $GITHUB_PATH + + - name: Install Noir + run: | + curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/noirup | bash -s -- \ + -C 51ae1b324cd73fdb4fe3695b5d483a44b4aff4a9 - name: Run nargo fmt run: nargo fmt --check - - check-noir: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Install Nargo - uses: noir-lang/noirup@v0.1.3 - with: - toolchain: nightly - + - name: Run nargo check - run: nargo check --silence-warnings - - test-noir: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Install Nargo - uses: noir-lang/noirup@v0.1.3 - with: - toolchain: nightly - + run: nargo check --silence-warnings + - name: Run nargo test - run: nargo test --silence-warnings \ No newline at end of file + run: nargo test --silence-warnings From 6969aa1959a36c32ab0df305ca7171407682008c Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Mon, 28 Oct 2024 18:18:08 +0200 Subject: [PATCH 03/10] perf: using comptime global --- crates/plume/src/expand_message_xmd.nr | 23 +++------ crates/plume/src/iso_map.nr | 70 ++++++++------------------ crates/plume/src/lib.nr | 2 +- crates/plume/src/map_to_curve.nr | 41 +++++---------- 4 files changed, 41 insertions(+), 95 deletions(-) diff --git a/crates/plume/src/expand_message_xmd.nr b/crates/plume/src/expand_message_xmd.nr index e6b54d5..e0e281e 100644 --- a/crates/plume/src/expand_message_xmd.nr +++ b/crates/plume/src/expand_message_xmd.nr @@ -8,6 +8,8 @@ use std::hash::sha256; +comptime global DST_PRIME: [u8; 50] = [81, 85, 85, 88, 45, 86, 48, 49, 45, 67, 83, 48, 50, 45, 119, 105, 116, 104, 45, 115, 101, 99, 112, 50, 53, 54, 107, 49, 95, 88, 77, 68, 58, 83, 72, 65, 45, 50, 53, 54, 95, 83, 83, 87, 85, 95, 82, 79, 95, 49]; + pub fn expand_message_xmd(msg: [u8; N]) -> [u8; 96] { let b0 = msg_prime(msg); let b1 = hash_b(1, b0); @@ -42,9 +44,8 @@ fn msg_prime(msg: [u8; N]) -> [u8; 32] { preimage[64 + N + 2] = 0; - let dst_prime = dst_prime(); - for i in 0..dst_prime.len() { - preimage[64 + N + 2 + 1 + i] = dst_prime[i]; + for i in 0..50 { + preimage[64 + N + 2 + 1 + i] = DST_PRIME[i]; } sha256(preimage) @@ -71,25 +72,13 @@ fn hash_b(b_idx: u8, b: [u8; 32]) -> [u8; 32] { preimage[32] = b_idx; - let dst_prime = dst_prime(); - for i in 0..dst_prime.len() { - preimage[32 + 1 + i] = dst_prime[i]; + for i in 0..50 { + preimage[32 + 1 + i] = DST_PRIME[i]; } sha256(preimage) } -// ****************** CONSTANTS ****************** // -// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#name-expand_message_xmdsha-256 - -fn dst_prime() -> [u8; 50] { - [ - 81, 85, 85, 88, 45, 86, 48, 49, 45, 67, 83, 48, 50, 45, 119, 105, 116, - 104, 45, 115, 101, 99, 112, 50, 53, 54, 107, 49, 95, 88, 77, 68, 58, - 83, 72, 65, 45, 50, 53, 54, 95, 83, 83, 87, 85, 95, 82, 79, 95, 49 - ] -} - #[test] fn test_b0() { let msg = [97, 98, 99]; // "abc" diff --git a/crates/plume/src/iso_map.nr b/crates/plume/src/iso_map.nr index 3836b39..e2ad046 100644 --- a/crates/plume/src/iso_map.nr +++ b/crates/plume/src/iso_map.nr @@ -10,6 +10,23 @@ use bignum::BigNum; use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fq}; use noir_bigcurve::BigCurve; +comptime global K1_0: Secp256k1Fq = BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa8c7, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]); +comptime global K1_1: Secp256k1Fq = BigNum::from_array([0x95d2fc0bf63b92dfff1044f17c6581, 0xd4c80bc321d5b9f315cea7fd44c5d5, 0x7d3]); +comptime global K1_2: Secp256k1Fq = BigNum::from_array([0x506144037c40314ecbd0b53d9dd262, 0x328d23f234e6e2a413deca25caece4, 0x534c]); +comptime global K1_3: Secp256k1Fq = BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa88c, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]); + +comptime global K2_0: Secp256k1Fq = BigNum::from_array([0xcd409542f8487d9fe6b745781eb49b, 0x71193d94918a9ca34ccbb7b640dd86, 0xd357]); +comptime global K2_1: Secp256k1Fq = BigNum::from_array([0xd36b641f5e41bbc52a56612a8c6d14, 0xc6f64383dc1df7c4b2d51b54225406, 0xedad]); + +comptime global K3_0: Secp256k1Fq = BigNum::from_array([0x684bda12f684bda12f684b8e38e23c, 0x12f684bda12f684bda12f684bda12f, 0x4bda]); +comptime global K3_1: Secp256k1Fq = BigNum::from_array([0x7ab046d686da6fdffc90fc201d71a3, 0xc32d5cb7c0fa9d0a54b12a0a6d564, 0xc75e]); +comptime global K3_2: Secp256k1Fq = BigNum::from_array([0x2830a201be2018a765e85a9ecee931, 0x194691f91a73715209ef6512e57672, 0x29a6]); +comptime global K3_3: Secp256k1Fq = BigNum::from_array([0xa12f684bda12f684bda12f38e38d84, 0x4bda12f684bda12f684bda12f684bd, 0x2f68]); + +comptime global K4_0: Secp256k1Fq = BigNum::from_array([0xfffffffffffffffffffffefffff93b, 0xffffffffffffffffffffffffffffff, 0xffff]); +comptime global K4_1: Secp256k1Fq = BigNum::from_array([0x67c1bfc8e8d978dfb425d2685c2573, 0x534bb8bdb49fd5e9e6632722c29894, 0x7a06]); +comptime global K4_2: Secp256k1Fq = BigNum::from_array([0x3d21162f0d6299a7bf8192bfd2a76f, 0xaa716545ca2cf3a70c3fa8fe337e0a, 0x6484]); + pub fn iso_map(p: Secp256k1) -> Secp256k1 { let x2 = p.x * p.x; let x3 = x2 * p.x; @@ -26,64 +43,19 @@ pub fn iso_map(p: Secp256k1) -> Secp256k1 { } fn x_num(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { - k1_0() + k1_1() * x + k1_2() * x2 + k1_3() * x3 + K1_0 + K1_1 * x + K1_2 * x2 + K1_3 * x3 } fn x_den(x: Secp256k1Fq, x2: Secp256k1Fq) -> Secp256k1Fq { - x2 + k2_1() * x + k2_0() + x2 + K2_1 * x + K2_0 } fn y_num(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { - k3_0() + k3_1() * x + k3_2() * x2 + k3_3() * x3 + K3_0 + K3_1 * x + K3_2 * x2 + K3_3 * x3 } fn y_den(x: Secp256k1Fq, x2: Secp256k1Fq, x3: Secp256k1Fq) -> Secp256k1Fq { - k4_0() + k4_1() * x + k4_2() * x2 + x3 -} - -// ****************** CONSTANTS ****************** // - -fn k1_0() -> Secp256k1Fq { - BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa8c7, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]) -} -fn k1_1() -> Secp256k1Fq { - BigNum::from_array([0x95d2fc0bf63b92dfff1044f17c6581, 0xd4c80bc321d5b9f315cea7fd44c5d5, 0x7d3]) -} -fn k1_2() -> Secp256k1Fq { - BigNum::from_array([0x506144037c40314ecbd0b53d9dd262, 0x328d23f234e6e2a413deca25caece4, 0x534c]) -} -fn k1_3() -> Secp256k1Fq { - BigNum::from_array([0xe38e38e38e38e38e38e38daaaaa88c, 0xe38e38e38e38e38e38e38e38e38e38, 0x8e38]) -} - -fn k2_0() -> Secp256k1Fq { - BigNum::from_array([0xcd409542f8487d9fe6b745781eb49b, 0x71193d94918a9ca34ccbb7b640dd86, 0xd357]) -} -fn k2_1() -> Secp256k1Fq { - BigNum::from_array([0xd36b641f5e41bbc52a56612a8c6d14, 0xc6f64383dc1df7c4b2d51b54225406, 0xedad]) -} - -fn k3_0() -> Secp256k1Fq { - BigNum::from_array([0x684bda12f684bda12f684b8e38e23c, 0x12f684bda12f684bda12f684bda12f, 0x4bda]) -} -fn k3_1() -> Secp256k1Fq { - BigNum::from_array([0x7ab046d686da6fdffc90fc201d71a3, 0xc32d5cb7c0fa9d0a54b12a0a6d564, 0xc75e]) -} -fn k3_2() -> Secp256k1Fq { - BigNum::from_array([0x2830a201be2018a765e85a9ecee931, 0x194691f91a73715209ef6512e57672, 0x29a6]) -} -fn k3_3() -> Secp256k1Fq { - BigNum::from_array([0xa12f684bda12f684bda12f38e38d84, 0x4bda12f684bda12f684bda12f684bd, 0x2f68]) -} - -fn k4_0() -> Secp256k1Fq { - BigNum::from_array([0xfffffffffffffffffffffefffff93b, 0xffffffffffffffffffffffffffffff, 0xffff]) -} -fn k4_1() -> Secp256k1Fq { - BigNum::from_array([0x67c1bfc8e8d978dfb425d2685c2573, 0x534bb8bdb49fd5e9e6632722c29894, 0x7a06]) -} -fn k4_2() -> Secp256k1Fq { - BigNum::from_array([0x3d21162f0d6299a7bf8192bfd2a76f, 0xaa716545ca2cf3a70c3fa8fe337e0a, 0x6484]) + K4_0 + K4_1 * x + K4_2 * x2 + x3 } #[test] diff --git a/crates/plume/src/lib.nr b/crates/plume/src/lib.nr index 8ac1ef7..967582c 100644 --- a/crates/plume/src/lib.nr +++ b/crates/plume/src/lib.nr @@ -12,7 +12,7 @@ use noir_bigcurve::BigCurve; use crate::hash_to_curve::hash_to_curve; -global G: Secp256k1 = BigCurve::one(); +comptime global G: Secp256k1 = BigCurve::one(); // r*G - r_point // r*h - hashed_to_curve_r diff --git a/crates/plume/src/map_to_curve.nr b/crates/plume/src/map_to_curve.nr index 29ea403..39c226e 100644 --- a/crates/plume/src/map_to_curve.nr +++ b/crates/plume/src/map_to_curve.nr @@ -10,19 +10,21 @@ use bignum::BigNum; use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fq, Secp256k1_Params}; use noir_bigcurve::BigCurve; +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-8.7 +comptime global Z: Secp256k1Fq = BigNum::from_array([0xfffffffffffffffffffffefffffc24, 0xffffffffffffffffffffffffffffff, 0xffff]); +comptime global A: Secp256k1Fq = BigNum::from_array([0x53d363cb6f0e5d405447c01a444533, 0x31abdd661adca08a5558f0f5d272e9, 0x3f87]); +comptime global B: Secp256k1Fq = BigNum::from_array([0x6eb, 0, 0]); + +comptime global ONE: Secp256k1Fq = BigNum::one(); + // Returns point E' isogeneous to secp256k1. pub fn map_to_curve(u: Secp256k1Fq) -> Secp256k1 { - let a = a(); - let b = b(); - let z = z(); - let one: Secp256k1Fq = BigNum::one(); + let tv1 = ONE / (Z * Z * u * u * u * u + Z * u * u); + let x1 = (B.neg() / A) * (ONE + tv1); - let tv1 = one / (z * z * u * u * u * u + z * u * u); - let x1 = (b.neg() / a) * (one + tv1); - - let gx1 = x1 * x1 * x1 + a * x1 + b; - let x2 = z * u * u * x1; - let gx2 = x2 * x2 * x2 + a * x2 + b; + let gx1 = x1 * x1 * x1 + A * x1 + B; + let x2 = Z * u * u * x1; + let gx2 = x2 * x2 * x2 + A * x2 + B; let (x, mut y) = select_xy(x1, x2, gx1, gx2); let ubyte: [u8; 32] = u.to_le_bytes(); @@ -64,28 +66,11 @@ fn select_xy( (x, y) } -// ****************** CONSTANTS ****************** // -// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-8.7 - -fn z() -> Secp256k1Fq { - BigNum::from_array([0xfffffffffffffffffffffefffffc24, 0xffffffffffffffffffffffffffffff, 0xffff]) -} - -// Weierstrass equation `a` parameter for curve E' isogeneous to secp256k1. -fn a() -> Secp256k1Fq { - BigNum::from_array([0x53d363cb6f0e5d405447c01a444533, 0x31abdd661adca08a5558f0f5d272e9, 0x3f87]) -} - -// Weierstrass equation `b` parameter for curve E' isogeneous to secp256k1. -fn b() -> Secp256k1Fq { - BigNum::from_array([0x6eb, 0, 0]) -} - #[test] fn test_inverse() { let value: Secp256k1Fq = BigNum::from_array([0x387936733e29cddb43759809208354, 0xc334daf72303fb27f6aad8201a9465, 0xc6f1]); - let actual = BigNum::one() / value; + let actual = ONE / value; let expected: [u8; 32] = [ 211, 142, 221, 78, 176, 90, 13, 18, From 8db2086bdcec9c00c2ddb3ea31c3a32c44ad8b7e Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Mon, 28 Oct 2024 18:27:46 +0200 Subject: [PATCH 04/10] ci: add caching for nargo --- .github/workflows/noir.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/noir.yml b/.github/workflows/noir.yml index 880ab49..3825491 100644 --- a/.github/workflows/noir.yml +++ b/.github/workflows/noir.yml @@ -18,6 +18,30 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 + - name: Cache Cargo Registry + uses: actions/cache@v4 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Cache Cargo Index + uses: actions/cache@v4 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-index- + + - name: Cache Nargo Build + uses: actions/cache@v4 + with: + path: ~/.nargo + key: ${{ runner.os }}-nargo-${{ hashFiles('Cargo.lock', 'noirup') }} + restore-keys: | + ${{ runner.os }}-nargo- + - name: Create `.nargo/bin` directory shell: bash run: | From 0e30caadb197fd135cc3e184a926e8c71a91c267 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Mon, 28 Oct 2024 18:48:29 +0200 Subject: [PATCH 05/10] fix: comment-out heavy tests --- crates/plume/src/lib.nr | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/plume/src/lib.nr b/crates/plume/src/lib.nr index 967582c..b9d6f38 100644 --- a/crates/plume/src/lib.nr +++ b/crates/plume/src/lib.nr @@ -175,6 +175,8 @@ fn test_nullifier() { assert(actual == expected); } +/* Too slow for CI. Run manually. + #[test] fn test_r_point() { let sk: Secp256k1Fr = BigNum::from_be_bytes( @@ -416,3 +418,4 @@ fn test_plume_v2() { plume_v2(msg, c2, s2, pk, nullifier); // assert inside the function } +*/ From 2fdb5074181b090ad31593520f37bbe0fcc830e5 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Mon, 28 Oct 2024 21:46:17 +0200 Subject: [PATCH 06/10] ci: set only nargo binary to be cached --- .github/workflows/noir.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/noir.yml b/.github/workflows/noir.yml index 3825491..35cd4df 100644 --- a/.github/workflows/noir.yml +++ b/.github/workflows/noir.yml @@ -17,30 +17,15 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - - - name: Cache Cargo Registry - uses: actions/cache@v4 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-registry- - - - name: Cache Cargo Index - uses: actions/cache@v4 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-index- - - name: Cache Nargo Build + - name: Cache Nargo Binary uses: actions/cache@v4 + id: nargo-cache with: - path: ~/.nargo - key: ${{ runner.os }}-nargo-${{ hashFiles('Cargo.lock', 'noirup') }} + path: ~/.nargo/bin/nargo + key: ${{ runner.os }}-nargo-binary restore-keys: | - ${{ runner.os }}-nargo- + ${{ runner.os }}-nargo-binary - name: Create `.nargo/bin` directory shell: bash @@ -49,6 +34,7 @@ jobs: echo "${HOME}/.nargo/bin" >> $GITHUB_PATH - name: Install Noir + if: steps.nargo-cache.outputs.cache-hit != 'true' run: | curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/noirup | bash -s -- \ -C 51ae1b324cd73fdb4fe3695b5d483a44b4aff4a9 From ce09987e385c563dc06e1c2af445dbdcca8b30bc Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Tue, 29 Oct 2024 00:36:43 +0200 Subject: [PATCH 07/10] refactor: remove a_div_b_pow_c --- crates/plume/src/lib.nr | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/crates/plume/src/lib.nr b/crates/plume/src/lib.nr index b9d6f38..681bbfb 100644 --- a/crates/plume/src/lib.nr +++ b/crates/plume/src/lib.nr @@ -44,21 +44,16 @@ fn check_ec_equations( let c: Secp256k1Scalar = ScalarField::from_bignum(c); let s_point = G.mul(s); - let r_point = a_div_b_pow_c(s_point, pk, c); + let r_point = s_point - pk.mul(c); let plume_msg = form_plume_msg(msg, pk); let hashed_to_curve = hash_to_curve(plume_msg); let h_pow_s = hashed_to_curve.mul(s); - let hashed_to_curve_r = a_div_b_pow_c(h_pow_s, nullifier, c); + let hashed_to_curve_r = h_pow_s - nullifier.mul(c); (r_point, hashed_to_curve_r, hashed_to_curve) } -fn a_div_b_pow_c(a: Secp256k1, b: Secp256k1, c: Secp256k1Scalar) -> Secp256k1 { - let b_pow_c = b.mul(c); - a + b_pow_c.neg() -} - fn form_plume_msg(msg: [u8; N], pk: Secp256k1) -> [u8; N + 33] { let mut plume_msg = [0; N + 33]; // 33 bytes for compressed pk @@ -203,7 +198,7 @@ fn test_r_point() { let pk = G.mul(sk); let s_point = G.mul(s); - let actual = a_div_b_pow_c(s_point, pk, c); + let actual = s_point - pk.mul(c); let expected: Secp256k1 = BigCurve { x: BigNum::from_be_bytes( @@ -289,7 +284,7 @@ fn test_hashed_to_curve_r() { let nullifier = H.mul(sk); let h_pow_s = H.mul(s); - let actual = a_div_b_pow_c(h_pow_s, nullifier, c); + let actual = h_pow_s - nullifier.mul(c); let expected : Secp256k1 = BigCurve { x: BigNum::from_be_bytes( From e43d4d4384de5afd1aa43018e12601277cd5e426 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Tue, 29 Oct 2024 02:30:20 +0200 Subject: [PATCH 08/10] feat!(): updated plume to return --- Nargo.toml | 2 +- crates/plume/src/expand_message_xmd.nr | 4 +- crates/plume/src/lib.nr | 104 ++++++++++++++----------- crates/use/src/main.nr | 30 ------- crates/{use => use_v1}/Nargo.toml | 4 +- crates/{use => use_v1}/Prover.toml | 0 crates/use_v1/src/main.nr | 29 +++++++ crates/use_v2/Nargo.toml | 12 +++ crates/use_v2/Prover.toml | 5 ++ crates/use_v2/src/main.nr | 33 ++++++++ etc/gen.sage | 4 +- etc/main.sage | 44 ++++------- 12 files changed, 159 insertions(+), 112 deletions(-) delete mode 100644 crates/use/src/main.nr rename crates/{use => use_v1}/Nargo.toml (84%) rename crates/{use => use_v1}/Prover.toml (100%) create mode 100644 crates/use_v1/src/main.nr create mode 100644 crates/use_v2/Nargo.toml create mode 100644 crates/use_v2/Prover.toml create mode 100644 crates/use_v2/src/main.nr diff --git a/Nargo.toml b/Nargo.toml index a04d00a..3b91469 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["crates/plume", "crates/use"] \ No newline at end of file +members = ["crates/plume", "crates/use_v1", "crates/use_v2"] \ No newline at end of file diff --git a/crates/plume/src/expand_message_xmd.nr b/crates/plume/src/expand_message_xmd.nr index e0e281e..1fced5e 100644 --- a/crates/plume/src/expand_message_xmd.nr +++ b/crates/plume/src/expand_message_xmd.nr @@ -81,7 +81,7 @@ fn hash_b(b_idx: u8, b: [u8; 32]) -> [u8; 32] { #[test] fn test_b0() { - let msg = [97, 98, 99]; // "abc" + let msg = [97, 98, 99]; let actual_b0 = msg_prime(msg); @@ -162,7 +162,7 @@ fn test_b3() { #[test] fn tests_expand_message_xmd() { - let msg = [97, 98, 99]; // "abc" + let msg = [97, 98, 99]; let actual = expand_message_xmd(msg); diff --git a/crates/plume/src/lib.nr b/crates/plume/src/lib.nr index 681bbfb..2654ace 100644 --- a/crates/plume/src/lib.nr +++ b/crates/plume/src/lib.nr @@ -13,36 +13,39 @@ use noir_bigcurve::BigCurve; use crate::hash_to_curve::hash_to_curve; comptime global G: Secp256k1 = BigCurve::one(); +comptime global COMPRESSED_SIZE_BYTES: u32 = 33; -// r*G - r_point -// r*h - hashed_to_curve_r -// sha256(G || Pk || H || N || r*G || r*H) -pub fn plume_v1(msg: [u8; N], c: [u8; 32], s: Secp256k1Scalar, pk: Secp256k1, nullifier: Secp256k1) { +pub fn plume_v1( + msg: [u8; N], + c: Secp256k1Scalar, + s: Secp256k1Scalar, + pk: Secp256k1, + nullifier: Secp256k1 +) -> [u8; 32] { let (r_point, hashed_to_curve_r, hashed_to_curve) = check_ec_equations(msg, c, s, pk, nullifier); - let actual_c = sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r); - assert(actual_c == c); + sha256_12_coordinates(pk, hashed_to_curve, nullifier, r_point, hashed_to_curve_r) } -// https://www.notion.so/mantanetwork/PLUME-Discussion-6f4b7e7cf63e4e33976f6e697bf349ff -pub fn plume_v2(msg: [u8; N], c2: [u8; 32], s2: Secp256k1Scalar, pk: Secp256k1, nullifier: Secp256k1) { - let (r_point, hashed_to_curve_r, _) = check_ec_equations(msg, c2, s2, pk, nullifier); - let actual_c2 = sha256_6_coordinates(nullifier, r_point, hashed_to_curve_r); +pub fn plume_v2( + msg: [u8; N], + c: Secp256k1Scalar, + s: Secp256k1Scalar, + pk: Secp256k1, + nullifier: Secp256k1 +) -> (Secp256k1, Secp256k1) { + let (r_point, hashed_to_curve_r, _) = check_ec_equations(msg, c, s, pk, nullifier); - assert(actual_c2 == c2); + (r_point, hashed_to_curve_r) } -// Return values - r_point, hashed_to_curve_r, hashed_to_curve fn check_ec_equations( msg: [u8; N], - c: [u8; 32], + c: Secp256k1Scalar, s: Secp256k1Scalar, pk: Secp256k1, nullifier: Secp256k1 ) -> (Secp256k1, Secp256k1, Secp256k1) { - let c: Secp256k1Fr = BigNum::from_be_bytes(c); - let c: Secp256k1Scalar = ScalarField::from_bignum(c); - let s_point = G.mul(s); let r_point = s_point - pk.mul(c); @@ -54,36 +57,37 @@ fn check_ec_equations( (r_point, hashed_to_curve_r, hashed_to_curve) } -fn form_plume_msg(msg: [u8; N], pk: Secp256k1) -> [u8; N + 33] { - let mut plume_msg = [0; N + 33]; // 33 bytes for compressed pk +fn form_plume_msg(msg: [u8; N], pk: Secp256k1) -> [u8; N + COMPRESSED_SIZE_BYTES] { + let mut plume_msg = [0; N + COMPRESSED_SIZE_BYTES]; for i in 0..N { plume_msg[i] = msg[i]; } let compressed_pk = compress_ec_point(pk); - for i in 0..33 { + for i in 0..COMPRESSED_SIZE_BYTES { plume_msg[N + i] = compressed_pk[i]; } plume_msg } -fn compress_ec_point(pk: Secp256k1) -> [u8; 33] { - let x: [u8; 32] = pk.x.to_le_bytes(); - let mut compressed = [0 as u8; 33]; +fn compress_ec_point(p: Secp256k1) -> [u8; COMPRESSED_SIZE_BYTES] { + let x: [u8; 32] = p.x.to_le_bytes(); + let mut compressed = [0 as u8; COMPRESSED_SIZE_BYTES]; - let tmp: [u8; 32] = pk.y.to_le_bytes(); - compressed[0] = (tmp[0] & 1) + 2; + let sign = p.y.to_le_bytes::<32>()[0] & 1; + compressed[0] = sign + 2; // convention to encode `y` as 02 or 03 for i in 0..32 { compressed[32-i] = x[i]; } + compressed } fn sha256_12_coordinates(pk: Secp256k1, h: Secp256k1, nullifier: Secp256k1, gr: Secp256k1, hr: Secp256k1) -> [u8; 32] { - let mut compressed = [[0 as u8; 33]; 6]; + let mut compressed = [[0 as u8; COMPRESSED_SIZE_BYTES]; 6]; compressed[0] = compress_ec_point(G); compressed[1] = compress_ec_point(pk); compressed[2] = compress_ec_point(h); @@ -92,28 +96,13 @@ fn sha256_12_coordinates(pk: Secp256k1, h: Secp256k1, nullifier: Secp256k1, gr: compressed[5] = compress_ec_point(hr); // Concatenate - let mut res = [0 as u8; 198]; + let mut res = [0 as u8; COMPRESSED_SIZE_BYTES * 6]; for i in 0..6 { - for j in 0..33 { - res[i*33 + j] = compressed[i][j]; + for j in 0..COMPRESSED_SIZE_BYTES { + res[i*COMPRESSED_SIZE_BYTES + j] = compressed[i][j]; } } - sha256(res) -} - -fn sha256_6_coordinates(nullifier: Secp256k1, gr: Secp256k1, hr: Secp256k1) -> [u8; 32] { - let mut compressed = [[0 as u8; 33]; 3]; - compressed[0] = compress_ec_point(nullifier); - compressed[1] = compress_ec_point(gr); - compressed[2] = compress_ec_point(hr); - // Concatenate - let mut res = [0 as u8; 99]; - for i in 0..3 { - for j in 0..33 { - res[i*33 + j] = compressed[i][j]; - } - } sha256(res) } @@ -347,9 +336,13 @@ fn test_plume_v1() { let msg = [ 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 ]; + let c = [ 198, 167, 252, 44, 146, 109, 219, 175, 32, 115, 26, 71, 159, 182, 86, 111, 45, 170, 85, 20, 186, 174, 82, 35, 254, 59, 50, 237, 188, 232, 50, 84 ]; + let expected = c; + let c: Secp256k1Fr = BigNum::from_be_bytes(c); + let c: Secp256k1Scalar = ScalarField::from_bignum(c); let s: Secp256k1Fr = BigNum::from_be_bytes( [ @@ -375,7 +368,9 @@ fn test_plume_v1() { let nullifier = H.mul(sk); - plume_v1(msg, c, s, pk, nullifier); // assert inside the function + let actual = plume_v1(msg, c, s, pk, nullifier); + + assert(expected == actual); } #[test] @@ -383,9 +378,13 @@ fn test_plume_v2() { let msg = [ 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 ]; + let c2 = [ 61, 191, 183, 23, 112, 80, 16, 212, 244, 74, 112, 114, 12, 149, 231, 75, 71, 91, 211, 167, 131, 171, 11, 158, 138, 107, 59, 54, 52, 52, 235, 150 ]; + let expected = c2; + let c2: Secp256k1Fr = BigNum::from_be_bytes(c2); + let c2: Secp256k1Scalar = ScalarField::from_bignum(c2); let s2: Secp256k1Fr = BigNum::from_be_bytes( [ @@ -411,6 +410,21 @@ fn test_plume_v2() { let nullifier = H.mul(sk); - plume_v2(msg, c2, s2, pk, nullifier); // assert inside the function + let (r_point, hashed_to_curve_r) = plume_v2(msg, c2, s2, pk, nullifier); + + let mut compressed = [[0 as u8; COMPRESSED_SIZE_BYTES]; 3]; + compressed[0] = compress_ec_point(nullifier); + compressed[1] = compress_ec_point(r_point); + compressed[2] = compress_ec_point(hashed_to_curve_r); + + let mut res = [0 as u8; COMPRESSED_SIZE_BYTES * 3]; + for i in 0..3 { + for j in 0..COMPRESSED_SIZE_BYTES { + res[i*COMPRESSED_SIZE_BYTES + j] = compressed[i][j]; + } + } + let actual = sha256(res); + + assert(expected == actual); } */ diff --git a/crates/use/src/main.nr b/crates/use/src/main.nr deleted file mode 100644 index 8edbfa8..0000000 --- a/crates/use/src/main.nr +++ /dev/null @@ -1,30 +0,0 @@ -use bignum::BigNum; -use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fr, Secp256k1Scalar}; -use noir_bigcurve::BigCurve; -use noir_bigcurve::scalar_field::ScalarField; - -use plume::{plume_v1, plume_v2}; - -global MSG_LEN: u32 = 32; - -pub fn main(msg: [u8; MSG_LEN], c: [u8; 32], s: [u8; 32], pk: [[u8; 32]; 2], nullifier: [[u8; 32]; 2]) { - let s: Secp256k1Fr = BigNum::from_be_bytes(s); - let s: Secp256k1Scalar = ScalarField::from_bignum(s); - - let pk: Secp256k1 = BigCurve { - x: BigNum::from_be_bytes(pk[0]), - y: BigNum::from_be_bytes(pk[1]), - is_infinity: false // we never pass inf in Prover.toml - }; - - let nullifier: Secp256k1 = BigCurve { - x: BigNum::from_be_bytes(nullifier[0]), - y: BigNum::from_be_bytes(nullifier[1]), - is_infinity: false // we never pass inf in Prover.toml - }; - - // Choose your plume variant and comment the other - - // plume_v1(msg, c, s, pk, nullifier); - plume_v2(msg, c, s, pk, nullifier); -} diff --git a/crates/use/Nargo.toml b/crates/use_v1/Nargo.toml similarity index 84% rename from crates/use/Nargo.toml rename to crates/use_v1/Nargo.toml index ba070d5..570fd95 100644 --- a/crates/use/Nargo.toml +++ b/crates/use_v1/Nargo.toml @@ -1,9 +1,9 @@ [package] -name = "use" +name = "use_v1" type = "bin" authors = ["Distributed Lab"] license = "MIT" -description = "PLUME usage in Noir." +description = "PLUME V1 usage in Noir." compiler_version = ">=0.35.0" [dependencies] diff --git a/crates/use/Prover.toml b/crates/use_v1/Prover.toml similarity index 100% rename from crates/use/Prover.toml rename to crates/use_v1/Prover.toml diff --git a/crates/use_v1/src/main.nr b/crates/use_v1/src/main.nr new file mode 100644 index 0000000..6d9fe94 --- /dev/null +++ b/crates/use_v1/src/main.nr @@ -0,0 +1,29 @@ +use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fr, Secp256k1Scalar}; +use noir_bigcurve::BigCurve; +use noir_bigcurve::scalar_field::ScalarField; + +use plume::plume_v1; + +global MSG_LEN: u32 = 32; + +pub fn main(msg: [u8; MSG_LEN], c: [u8; 32], s: [u8; 32], pk: [[u8; 32]; 2], nullifier: [[u8; 32]; 2]) { + let actual_c = plume_v1( + msg, + as_scalar(c), + as_scalar(s), + as_point(pk), + as_point(nullifier) + ); + + assert(c == actual_c); +} + +fn as_scalar(bytes: [u8; 32]) -> Secp256k1Scalar { + let scalar: Secp256k1Fr = BigNum::from_be_bytes(bytes); + ScalarField::from_bignum(scalar) +} + +fn as_point(bytes: [[u8; 32]; 2]) -> Secp256k1 { + BigCurve { x: BigNum::from_be_bytes(bytes[0]), y: BigNum::from_be_bytes(bytes[1]), is_infinity: false } +} diff --git a/crates/use_v2/Nargo.toml b/crates/use_v2/Nargo.toml new file mode 100644 index 0000000..d130e2c --- /dev/null +++ b/crates/use_v2/Nargo.toml @@ -0,0 +1,12 @@ +[package] +name = "use_v2" +type = "bin" +authors = ["Distributed Lab"] +license = "MIT" +description = "PLUME V2 usage in Noir." +compiler_version = ">=0.35.0" + +[dependencies] +plume = { path = "../plume" } +bignum = {tag = "v0.3.7", git = "https://github.com/noir-lang/noir-bignum"} +noir_bigcurve = {tag = "v0.4", git = "https://github.com/noir-lang/noir_bigcurve"} \ No newline at end of file diff --git a/crates/use_v2/Prover.toml b/crates/use_v2/Prover.toml new file mode 100644 index 0000000..eeb23f2 --- /dev/null +++ b/crates/use_v2/Prover.toml @@ -0,0 +1,5 @@ +c = ["168", "116", "35", "227", "254", "249", "247", "14", "215", "165", "253", "2", "36", "152", "193", "128", "30", "107", "188", "237", "197", "68", "104", "158", "158", "156", "208", "146", "190", "131", "18", "210"] +msg = ["71", "62", "193", "198", "189", "18", "238", "214", "120", "50", "134", "210", "241", "249", "251", "22", "116", "126", "6", "32", "254", "247", "62", "236", "60", "225", "51", "255", "89", "134", "236", "180"] +nullifier = [["78", "91", "85", "215", "95", "183", "229", "168", "164", "18", "237", "152", "227", "223", "125", "177", "67", "17", "192", "55", "65", "182", "38", "246", "15", "42", "102", "30", "137", "240", "76", "181"], ["231", "226", "233", "230", "142", "221", "98", "228", "110", "112", "42", "93", "232", "186", "118", "81", "93", "98", "34", "102", "34", "69", "174", "111", "250", "195", "245", "116", "217", "145", "39", "137"]] +pk = [["13", "234", "84", "185", "203", "217", "7", "132", "174", "234", "190", "150", "56", "131", "166", "137", "163", "120", "187", "69", "156", "185", "37", "243", "197", "211", "203", "9", "213", "210", "127", "141"], ["165", "51", "20", "1", "6", "136", "42", "19", "55", "106", "239", "105", "87", "56", "235", "203", "119", "130", "202", "249", "73", "235", "208", "177", "109", "88", "214", "37", "246", "71", "40", "142"]] +s = ["164", "9", "146", "60", "252", "221", "204", "161", "50", "107", "197", "91", "94", "81", "106", "37", "174", "245", "190", "3", "88", "66", "2", "60", "91", "3", "7", "44", "203", "241", "49", "91"] diff --git a/crates/use_v2/src/main.nr b/crates/use_v2/src/main.nr new file mode 100644 index 0000000..b31c318 --- /dev/null +++ b/crates/use_v2/src/main.nr @@ -0,0 +1,33 @@ +use bignum::BigNum; +use noir_bigcurve::curves::secp256k1::{Secp256k1, Secp256k1Fr, Secp256k1Scalar}; +use noir_bigcurve::BigCurve; +use noir_bigcurve::scalar_field::ScalarField; + +use plume::plume_v2; + +global MSG_LEN: u32 = 32; + +pub fn main( + msg: [u8; MSG_LEN], + c: [u8; 32], + s: [u8; 32], + pk: [[u8; 32]; 2], + nullifier: [[u8; 32]; 2] +) -> pub (Secp256k1, Secp256k1) { + plume_v2( + msg, + as_scalar(c), + as_scalar(s), + as_point(pk), + as_point(nullifier) + ) +} + +fn as_scalar(bytes: [u8; 32]) -> Secp256k1Scalar { + let scalar: Secp256k1Fr = BigNum::from_be_bytes(bytes); + ScalarField::from_bignum(scalar) +} + +fn as_point(bytes: [[u8; 32]; 2]) -> Secp256k1 { + BigCurve { x: BigNum::from_be_bytes(bytes[0]), y: BigNum::from_be_bytes(bytes[1]), is_infinity: false } +} diff --git a/etc/gen.sage b/etc/gen.sage index 51bdca0..55eed40 100644 --- a/etc/gen.sage +++ b/etc/gen.sage @@ -19,7 +19,7 @@ def generate_random_r_sk_msg(msg_len: int): msg = os.urandom(msg_len) return (list(r), list(sk), list(msg)) -def plume_generate_test_case(version1: bool, msg_len: int): +def plume_generate_test_case(is_v1: bool, msg_len: int): (r, sk, msg) = generate_random_r_sk_msg(msg_len) r = bytes_to_num(r) sk = bytes_to_num(sk) @@ -33,7 +33,7 @@ def plume_generate_test_case(version1: bool, msg_len: int): Hp = E(H[0], H[1]) N = (sk * Hp).xy() - if version1: + if is_v1: c = sha256_points([G, Pk, H, N, r*G, r*Hp]) else: c = sha256_points([N, r*G, r*Hp]) diff --git a/etc/main.sage b/etc/main.sage index 3d82774..a1975bf 100644 --- a/etc/main.sage +++ b/etc/main.sage @@ -20,9 +20,13 @@ def format_array(arr): def format_double_array(pk): return "[" + ", ".join(format_array(subarr) for subarr in pk) + "]" -def update_prover_toml(filepath, version1: bool, msg_len: int): - data = toml.load(filepath) - (msg, c, s, pk, nullifier) = plume_generate_test_case(version1, msg_len) +def update_prover_toml(is_v1: bool, msg_len: int): + prover_toml_path = "../crates/use_v2/Prover.toml" + if is_v1: + path = "../crates/use_v1/Prover.toml" + + data = toml.load(prover_toml_path) + (msg, c, s, pk, nullifier) = plume_generate_test_case(is_v1, msg_len) data['c'] = c data['msg'] = msg @@ -36,35 +40,18 @@ def update_prover_toml(filepath, version1: bool, msg_len: int): pk_str = format_double_array(pk) s_str = format_array(s) - with open(filepath, 'w') as f: + with open(prover_toml_path, 'w') as f: f.write(f'c = {c_str}\n') f.write(f'msg = {msg_str}\n') f.write(f'nullifier = {nullifier_str}\n') f.write(f'pk = {pk_str}\n') f.write(f's = {s_str}\n') -def update_plume_version(is_v1: bool): - path = "../crates/use/src/" - # start from line 0 - p1_line = 27 - p2_line = 28 - - with open(path + 'main.nr', 'r') as file: - lines = file.readlines() - +def update_MSG_LEN_variable(is_v1: bool, msg_len: int): + path = "../crates/use_v2/src/" if is_v1: - lines[p1_line] = " plume_v1(msg, c, s, pk, nullifier);\n" - lines[p2_line] = " // plume_v2(msg, c, s, pk, nullifier);\n" - else: - lines[p1_line] = " // plume_v1(msg, c, s, pk, nullifier);\n" - lines[p2_line] = " plume_v2(msg, c, s, pk, nullifier);\n" - - with open(path + 'main.nr', 'w') as file: - file.writelines(lines) - - -def update_MSG_LEN_variable(msg_len: int): - path = "../crates/use/src/" + path = "../crates/use_v1/src/" + with open(path + 'main.nr', 'r') as file: lines = file.readlines() @@ -74,10 +61,8 @@ def update_MSG_LEN_variable(msg_len: int): with open(path + 'main.nr', 'w') as file: file.writelines(lines) - # Take MSG_LEN number and plume version (v1 or v2) if __name__ == "__main__": - prover_toml_path = "../crates/use/Prover.toml" if len(sys.argv) != 3: print("Error: incorrect number of arguments") sys.exit() @@ -91,6 +76,5 @@ if __name__ == "__main__": is_v1 = sys.argv[1] == versions[0] msg_len = int(sys.argv[2]) - update_plume_version(is_v1) - update_MSG_LEN_variable(msg_len) - update_prover_toml(prover_toml_path, is_v1, msg_len) + update_MSG_LEN_variable(is_v1, msg_len) + update_prover_toml(is_v1, msg_len) From 0487e627c30bbfaa05339d2071181cb3bb5c0f16 Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Tue, 29 Oct 2024 03:34:29 +0200 Subject: [PATCH 09/10] chore: added benchmarking script and updated some info --- Makefile | 33 -------------- README.md | 60 ++++---------------------- bench.sh | 91 +++++++++++++++++++++++++++++++++++++++ crates/use_v1/Prover.toml | 10 ++--- crates/use_v2/Prover.toml | 10 ++--- etc/README.md | 11 ++--- etc/main.sage | 2 +- 7 files changed, 114 insertions(+), 103 deletions(-) delete mode 100644 Makefile create mode 100755 bench.sh diff --git a/Makefile b/Makefile deleted file mode 100644 index a41555c..0000000 --- a/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -.PHONY: execute prove prove_ultra_honk verify write_vk_ultra_honk verify_ultra_honk write_vk verify zk zk_ultra_honk - -execute: - nargo execute plume --silence-warnings - -prove_ultra_honk: - bb prove_ultra_honk -b ./target/use.json -w ./target/plume.gz -o ./target/proof - -prove: - bb prove -b ./target/use.json -w ./target/plume.gz -o ./target/proof - -write_vk_ultra_honk: - bb write_vk_ultra_honk -b ./target/use.json -o ./target/vk - -verify_ultra_honk: - bb verify_ultra_honk -k ./target/vk -p ./target/proof - -write_vk: - bb write_vk -b ./target/use.json -o ./target/vk - -verify: - bb verify -k ./target/vk -p ./target/proof - - -zk_ultra_honk: - make execute - make prove_ultra_honk - make verify_ultra_honk - -zk: - make execute - make prove - make verify \ No newline at end of file diff --git a/README.md b/README.md index 242a176..ed77199 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Plume in Noir +# PLUME in Noir [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Noir CI 🌌](https://github.com/distributed-lab/noir-plume/actions/workflows/noir.yml/badge.svg)](https://github.com/distributed-lab/noir-plume/actions/workflows/noir.yml) Plume is needed to confirm your identity without disclosing your private data, i.e. [zero-knowledge proof](https://en.wikipedia.org/wiki/Zero-knowledge_proof). Plume has another feature: you can send a message from a private group using special group message. For more details visit . -## How to use? +## Eager to try? 😎 ### Add dependency to your project's `Nargo.toml` @@ -33,60 +33,18 @@ use plume::plume_v2; plume_v2(msg, c, s, pk, nullifier); ``` -### Example +### Examples -See the example in `crates/use`. For proving data generation, check out our `SageMath` [implementation](./etc). +Check out how to generate proofs with PLUME in either `crates/use_v1` or `crates/use_v2`. +For proving data generation, see our `SageMath` [implementation](./etc). -## Benchmark +## Benchmark 📊 We have provided information regarding different computational statistics such as constraints amount and time for various activities, see [Benchmark.md](./BENCHMARK.md) -## Miscellaneous +## There is more? 🤯 -### Message Lenght Restriction - -Due to `Noir` specifics and generics limitations, message length is hardcoded to be constant value `32`. -In case you need to change it, see [constants.nr](./crates/plume/src/constants.nr). - -### Cryptography - -In order to bring in `PLUME` to `Noir`, we needed to implement `secp256k1_XMD:SHA-256_SSWU_RO_` hash-to-curve algorithm. +In order to bring in `PLUME` to `Noir`, we needed to implement `secp256k1_XMD:SHA-256_SSWU_RO_` hash-to-curve algorithm, ergo now it is available in `Noir` ecosystem! Based on [this description](https://datatracker.ietf.org/doc/id/draft-irtf-cfrg-hash-to-curve-06.html). -Testes using [this data](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#appendix-J.8.1). - -#### The algorithm - -```bash -hash_to_curve(msg) - -Input: msg, an arbitrary-length byte string. -Output: P, a point in the secp256k1 curve. - -Steps: -1. u = hash_to_field(msg) -2. Q0 = map_to_curve(u[0]) -3. Q1 = map_to_curve(u[1]) -4. P = iso_map(Q0) + iso_map(Q1) -5. return P -``` - -##### hash_to_field - -Implemented in [hash_to_field.nr](crates/plume/src/hash_to_field.nr). -Follows the algorithm described [here](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#hashtofield). - -##### map_to_curve - -Implemented in [map_to_curve.nr](crates/plume/src/map_to_curve.nr). -Follows the algorithm described [here](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#simple-swu). - -##### iso_map - -Implemented in [iso_map.nr](crates/plume/src/iso_map.nr). -Follows the algorithm described [here](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#appx-iso-secp256k1). - -##### Elliptic Curve operations - -Implemented in [ec_ops.nr](crates/plume/src/ec_ops.nr). -Follows the algorithm described [here](https://www.rareskills.io/post/elliptic-curve-addition). +Tested using [this data](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#appendix-J.8.1). diff --git a/bench.sh b/bench.sh new file mode 100755 index 0000000..9867b1b --- /dev/null +++ b/bench.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -e # Exit immediately if a command exits with a non-zero status +export TIMEFORMAT="%R" + +VERSIONS=("v1" "v2") +PROOF_SYSTEMS=("ultra-plonk" "ultra-honk") + +# Initialize arrays to store timings +compilation_times=() +execution_times=() +proof_times=() +vk_times=() +verify_times=() +proof_system_names=() +version_names=() + +for VERSION in "${VERSIONS[@]}"; do + echo "Benchmarking PLUME $VERSION" + + echo "Compiling and executing the PLUME $VERSION circuit" + + # Compilation + compilation_time=$( { time nargo compile --force --silence-warnings --package use_$VERSION >/dev/null; } 2>&1 ) + compilation_times+=("$compilation_time") + + # Execution + execution_time=$( { time nargo execute --silence-warnings --package use_$VERSION use_$VERSION >/dev/null; } 2>&1 ) + execution_times+=("$execution_time") + + for PROOF_SYSTEM in "${PROOF_SYSTEMS[@]}"; do + echo "Proving, writing the verification key, and verifying the PLUME $VERSION circuit with $PROOF_SYSTEM" + + # Set command prefixes and suffixes based on the proof system + if [ "$PROOF_SYSTEM" == "ultra-plonk" ]; then + PROVE_CMD="bb prove" + VK_CMD="bb write_vk" + VERIFY_CMD="bb verify" + SUFFIX="_up" + PROOF_SYSTEM_NAME="Ultra-Plonk" + else + PROVE_CMD="bb prove_ultra_honk" + VK_CMD="bb write_vk_ultra_honk" + VERIFY_CMD="bb verify_ultra_honk" + SUFFIX="_uh" + PROOF_SYSTEM_NAME="Ultra-Honk" + fi + + # Define file paths + BASE_PATH="./target/use_$VERSION" + PROOF_PATH="./target/proof_${VERSION}${SUFFIX}" + VK_PATH="./target/vk_${VERSION}${SUFFIX}" + + # Proof Generation + proof_time=$( { time $PROVE_CMD -b "${BASE_PATH}.json" -w "${BASE_PATH}.gz" -o "$PROOF_PATH" >/dev/null; } 2>&1 ) + proof_times+=("$proof_time") + + # Verification Key Writing + vk_time=$( { time $VK_CMD -b "${BASE_PATH}.json" -o "$VK_PATH" >/dev/null; } 2>&1 ) + vk_times+=("$vk_time") + + # Verification + verify_time=$( { time $VERIFY_CMD -k "$VK_PATH" -p "$PROOF_PATH" >/dev/null; } 2>&1 ) + verify_times+=("$verify_time") + + proof_system_names+=("$PROOF_SYSTEM_NAME") + version_names+=("$VERSION") + done +done + +# Print the summary of timings +echo +echo "Benchmarking Summary:" + +array_index=0 +for (( i=0; i<${#VERSIONS[@]}; i++ )); do + VERSION="${VERSIONS[i]}" + echo "PLUME $VERSION:" + echo " Compilation time: ${compilation_times[i]} seconds" + echo " Execution time: ${execution_times[i]} seconds" + + for (( j=0; j<${#PROOF_SYSTEMS[@]}; j++ )); do + PROOF_SYSTEM_NAME="${proof_system_names[array_index]}" + echo " $PROOF_SYSTEM_NAME:" + echo " Proof generation time: ${proof_times[array_index]} seconds" + echo " Verification key writing time: ${vk_times[array_index]} seconds" + echo " Verification time: ${verify_times[array_index]} seconds" + ((array_index++)) + done + echo +done diff --git a/crates/use_v1/Prover.toml b/crates/use_v1/Prover.toml index a6a523e..ae55478 100644 --- a/crates/use_v1/Prover.toml +++ b/crates/use_v1/Prover.toml @@ -1,5 +1,5 @@ -c = ["53", "56", "241", "116", "247", "113", "134", "213", "193", "65", "151", "45", "21", "170", "18", "59", "83", "109", "226", "121", "204", "173", "236", "64", "86", "232", "242", "15", "37", "79", "226", "74"] -msg = ["74", "223", "32", "97", "177", "144", "197", "10", "58", "198", "201", "30", "96", "107", "23", "69", "13", "126", "108", "203", "33", "201", "101", "66", "77", "36", "65", "227", "36", "83", "187", "226"] -nullifier = [["88", "233", "237", "83", "167", "202", "118", "205", "248", "169", "110", "84", "82", "60", "243", "41", "186", "189", "121", "112", "11", "164", "13", "111", "47", "243", "131", "251", "46", "224", "116", "137"], ["213", "22", "193", "70", "149", "43", "149", "112", "12", "166", "64", "241", "242", "212", "208", "68", "219", "81", "135", "45", "243", "219", "210", "228", "72", "201", "68", "69", "29", "170", "234", "62"]] -pk = [["122", "186", "229", "218", "55", "150", "127", "92", "250", "27", "108", "44", "82", "215", "6", "183", "221", "50", "219", "205", "186", "5", "163", "196", "63", "106", "19", "156", "154", "244", "11", "59"], ["92", "161", "30", "116", "247", "146", "29", "73", "133", "16", "205", "120", "8", "179", "162", "43", "147", "97", "7", "224", "250", "135", "172", "135", "197", "131", "205", "59", "32", "113", "80", "126"]] -s = ["40", "27", "33", "89", "224", "169", "181", "143", "183", "9", "88", "211", "137", "93", "74", "178", "220", "18", "255", "20", "38", "254", "62", "187", "116", "253", "98", "243", "232", "163", "208", "23"] +c = ["216", "118", "145", "136", "91", "4", "222", "116", "104", "12", "106", "187", "190", "242", "23", "160", "145", "79", "64", "36", "137", "68", "67", "40", "36", "148", "218", "32", "143", "73", "204", "117"] +msg = ["78", "144", "86", "203", "136", "176", "142", "202", "13", "231", "136", "140", "230", "246", "201", "84", "37", "14", "86", "181", "47", "135", "224", "160", "104", "238", "248", "175", "110", "33", "167", "28"] +nullifier = [["148", "173", "27", "47", "88", "231", "178", "194", "118", "60", "241", "202", "54", "249", "171", "223", "125", "20", "188", "3", "146", "107", "75", "52", "46", "250", "78", "248", "107", "106", "215", "130"], ["13", "64", "28", "120", "252", "184", "118", "45", "251", "190", "134", "128", "88", "154", "188", "127", "222", "247", "124", "180", "52", "155", "36", "216", "160", "165", "157", "100", "139", "252", "148", "241"]] +pk = [["61", "255", "45", "182", "240", "139", "216", "171", "63", "196", "181", "37", "57", "74", "197", "53", "116", "27", "185", "236", "208", "115", "25", "185", "218", "227", "60", "193", "3", "246", "244", "93"], ["52", "22", "83", "206", "10", "220", "93", "188", "208", "32", "144", "236", "29", "103", "110", "222", "229", "48", "72", "213", "41", "234", "47", "10", "148", "104", "28", "215", "230", "20", "42", "118"]] +s = ["31", "240", "219", "166", "219", "231", "17", "13", "124", "15", "221", "231", "83", "171", "188", "50", "208", "0", "26", "38", "200", "138", "134", "86", "114", "207", "166", "21", "172", "173", "22", "12"] diff --git a/crates/use_v2/Prover.toml b/crates/use_v2/Prover.toml index eeb23f2..ea51f9b 100644 --- a/crates/use_v2/Prover.toml +++ b/crates/use_v2/Prover.toml @@ -1,5 +1,5 @@ -c = ["168", "116", "35", "227", "254", "249", "247", "14", "215", "165", "253", "2", "36", "152", "193", "128", "30", "107", "188", "237", "197", "68", "104", "158", "158", "156", "208", "146", "190", "131", "18", "210"] -msg = ["71", "62", "193", "198", "189", "18", "238", "214", "120", "50", "134", "210", "241", "249", "251", "22", "116", "126", "6", "32", "254", "247", "62", "236", "60", "225", "51", "255", "89", "134", "236", "180"] -nullifier = [["78", "91", "85", "215", "95", "183", "229", "168", "164", "18", "237", "152", "227", "223", "125", "177", "67", "17", "192", "55", "65", "182", "38", "246", "15", "42", "102", "30", "137", "240", "76", "181"], ["231", "226", "233", "230", "142", "221", "98", "228", "110", "112", "42", "93", "232", "186", "118", "81", "93", "98", "34", "102", "34", "69", "174", "111", "250", "195", "245", "116", "217", "145", "39", "137"]] -pk = [["13", "234", "84", "185", "203", "217", "7", "132", "174", "234", "190", "150", "56", "131", "166", "137", "163", "120", "187", "69", "156", "185", "37", "243", "197", "211", "203", "9", "213", "210", "127", "141"], ["165", "51", "20", "1", "6", "136", "42", "19", "55", "106", "239", "105", "87", "56", "235", "203", "119", "130", "202", "249", "73", "235", "208", "177", "109", "88", "214", "37", "246", "71", "40", "142"]] -s = ["164", "9", "146", "60", "252", "221", "204", "161", "50", "107", "197", "91", "94", "81", "106", "37", "174", "245", "190", "3", "88", "66", "2", "60", "91", "3", "7", "44", "203", "241", "49", "91"] +c = ["134", "240", "195", "22", "204", "198", "89", "57", "45", "204", "229", "224", "180", "36", "31", "83", "43", "157", "50", "199", "9", "72", "180", "141", "183", "98", "22", "88", "85", "111", "196", "95"] +msg = ["62", "9", "128", "210", "216", "31", "212", "145", "212", "204", "176", "89", "122", "123", "17", "11", "231", "171", "174", "211", "39", "82", "205", "229", "119", "125", "179", "74", "131", "66", "112", "69"] +nullifier = [["25", "148", "127", "98", "237", "6", "156", "138", "203", "120", "246", "140", "212", "59", "19", "136", "233", "162", "56", "144", "40", "31", "64", "159", "91", "62", "89", "88", "78", "190", "72", "252"], ["21", "32", "121", "57", "220", "94", "234", "215", "154", "206", "142", "118", "163", "161", "189", "61", "162", "175", "118", "173", "98", "67", "189", "118", "10", "158", "16", "128", "246", "63", "84", "222"]] +pk = [["22", "37", "199", "63", "92", "79", "168", "124", "56", "245", "179", "63", "36", "245", "105", "148", "254", "118", "69", "129", "135", "146", "226", "240", "104", "152", "215", "230", "190", "228", "63", "181"], ["43", "75", "38", "134", "210", "182", "69", "102", "199", "29", "243", "155", "87", "8", "16", "84", "188", "254", "2", "212", "227", "89", "252", "117", "195", "95", "242", "111", "193", "198", "165", "85"]] +s = ["240", "43", "180", "90", "190", "52", "21", "88", "231", "208", "113", "202", "39", "100", "104", "70", "13", "194", "197", "35", "241", "65", "143", "214", "4", "233", "73", "70", "198", "153", "201", "211"] diff --git a/etc/README.md b/etc/README.md index 5ee41a6..aa75d8f 100644 --- a/etc/README.md +++ b/etc/README.md @@ -8,16 +8,11 @@ To streamline demonstration of `PLUME` usage in `Noir`, we attach the below scri ### Generation of the `Prover.toml` data -Generates random 32-byte values of `r` and `sk`, random message-length dependent `msg` and computes other necessary information -for ZKP issuing. - -### Managing `PLUME` version - -Comments out the code in `/crates/use/src/main.nr` enabling either `v1` or `v2` version. +Generates random 32-byte values of `r` and `sk`, random message-length dependent `msg` and computes other necessary information for ZKP issuing. ### Managing message length -Changes `MSG_LEN` constant in `crates/plume/src/constants.nr`. +Changes `MSG_LEN` constant in either `crates/use_v1/src/main.nr` or `crates/use_v2/src/main.nr`. ## How to use? @@ -27,7 +22,7 @@ Install SageMath by following [these instructions](https://doc.sagemath.org/html ### Launch Sage -Select the version of plume you want to run: either "v1" or "v2", then the number of bytes for msg (non-negative number) and run `main.sage` supplying these as CLI arguments, for example: +Select the desired version of plume: either "v1" or "v2", then the number of bytes for msg (non-negative number) and run `main.sage` supplying these as CLI arguments, for example: ```bash sage main.sage v2 32 diff --git a/etc/main.sage b/etc/main.sage index a1975bf..9c5ed13 100644 --- a/etc/main.sage +++ b/etc/main.sage @@ -23,7 +23,7 @@ def format_double_array(pk): def update_prover_toml(is_v1: bool, msg_len: int): prover_toml_path = "../crates/use_v2/Prover.toml" if is_v1: - path = "../crates/use_v1/Prover.toml" + prover_toml_path = "../crates/use_v1/Prover.toml" data = toml.load(prover_toml_path) (msg, c, s, pk, nullifier) = plume_generate_test_case(is_v1, msg_len) From 07d21a8e9d46f23e003f1edc919573c59a42edbb Mon Sep 17 00:00:00 2001 From: Nikita Masych Date: Tue, 29 Oct 2024 14:56:14 +0200 Subject: [PATCH 10/10] chore: added benchmark for v1.0.0 --- BENCHMARK.md | 78 ++++++++++++++++++++++++--------------- README.md | 2 +- crates/use_v1/Prover.toml | 10 ++--- crates/use_v2/Prover.toml | 10 ++--- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/BENCHMARK.md b/BENCHMARK.md index 815217b..ffafcd0 100644 --- a/BENCHMARK.md +++ b/BENCHMARK.md @@ -2,13 +2,38 @@ > Computational statistics. -## Noir v0.35.0 Barrettenberg v0.56.0 +## v1.0.0 + +_Machine_: `MacBook Pro M2 Max 32 GB RAM 1 TB Storage` + +_Maximum RAM consumption_: `15 GB` + +_Noir_: 0.35.0+51ae1b324cd73fdb4fe3695b5d483a44b4aff4a9 + +_Barrettenberg_: 0.56.0 + +--- + +| Version | Message Length | ACIR Opcodes | Brillig Opcodes | Compilation Time | Execution Time | Ultra Plonk Proof Time | Ultra Plonk VK Writing Time | Ultra Plonk Verification Time | Ultra Honk Proof Time | Ultra Honk VK Writing Time | Ultra Honk Verification Time | +|---------|----------------|--------------|-----------------|------------------|----------------|------------------------|-----------------------------|-------------------------------|-----------------------|----------------------------|------------------------------| +| v1 | 32 | 217,057 | 468,974 | 50.460 seconds | 30.207 seconds | 10.076 seconds | 9.385 seconds | 0.030 seconds | 4.786 seconds | 3.621 seconds | 0.037 seconds | +| v2 | 32 | 215,215 | 468,628 | 42.989 seconds | 30.330 seconds | 9.673 seconds | 9.024 seconds | 0.029 seconds | 4.734 seconds | 3.620 seconds | 0.035 seconds | +| v1 | 100 | 217,447 | 469,042 | 54.699 seconds | 30.496 seconds | 9.968 seconds | 9.598 seconds | 0.031 seconds | 4.791 seconds | 3.769 seconds | 0.038 seconds | +| v2 | 100 | 215,605 | 468,696 | 45.778 seconds | 30.393 seconds | 10.110 seconds | 9.519 seconds | 0.029 seconds | 4.795 seconds | 3.723 seconds | 0.038 seconds | +| v1 | 10,000 | 274,871 | 478,942 | 73.138 seconds | 38.606 seconds | 35.419 seconds | 33.338 seconds | 0.033 seconds | 13.728 seconds | 11.027 seconds | 0.039 seconds | +| v2 | 10,000 | 273,029 | 478,596 | 65.427 seconds | 39.092 seconds | 35.247 seconds | 33.148 seconds | 0.029 seconds | 14.097 seconds | 11.159 seconds | 0.036 seconds | + +## v0.1.2 _Machine_: `20 Cores, 300 GB RAM` _Maximum RAM consumption_: `200 GB` -## Table +_Noir_: 0.35.0+51ae1b324cd73fdb4fe3695b5d483a44b4aff4a9 + +_Barrettenberg_: 0.56.0 + +--- | Version | Message Length | Constraints | Execution Time | Proving Ultra Plonk Time | Writing VK Ultra Plonk Time | Verifying Ultra Plonk Time | Proving Ultra Honk Time | Writing Vk Ultra Honk Time | Verifying Ultra Honk Time | |---------|----------------|-------------|--------------------|--------------------|--------------------|----------------|-------------------------|----------------------------|---------------------------| @@ -19,40 +44,33 @@ _Maximum RAM consumption_: `200 GB` | v1 | 10000 | 754,652 | 56 minutes 22 seconds | 2 minutes 27 seconds | 2 minutes 19 seconds | 0.12 seconds | 1 minute 16 seconds | 1 minute 2 seconds | 0.08 seconds | | v2 | 10000 | 753,998 | 56 minutes 16 seconds | 2 minutes 25 seconds | 2 minutes 20 seconds | 0.07 seconds | 1 minute 12 seconds | 1 minute 3 seconds | 0.08 seconds | -## Noir v0.33.0 Barrettenberg v0.47.1 +## v0.1.0 _Machine_: `20 Cores, 144 GB RAM` -_Maximum RAM consumption_: `43 GB` +_Maximum RAM consumption_: `123 GB` -## Table (Ultra Honk) +Ultra Plonk: -| Version | Message Length | Constraints | Execution Time | Proving Time | Writing VK Time | Verifying Time | -|---------|----------------|-------------|--------------------|--------------------|--------------------|----------------| -| v1 | 5 | 2,998,712 | 13 minute 56 seconds | 13 minutes 23 seconds | 12 minutes 3 seconds | 0.06 seconds | -| v2 | 5 | 2,998,520 | 13 minutes 52 seconds | 13 minutes 9 seconds | 12 minutes 14 seconds | 0.06 seconds | -| v1 | 32 | 2,998,905 | 14 minutes 14 seconds | 13 minutes 3 seconds | 11 minutes 44 seconds | 0.06 seconds | -| v2 | 32 | 2,998,636 | 14 minutes 5 seconds | 12 minutes 55 seconds | 11 minutes 48 seconds | 0.06 seconds | -| v1 | 100 | 2,999,162 | 14 minutes 44 seconds | 13 minutes 4 seconds | 12 minutes 30 seconds | 0.06 seconds | -| v2 | 100 | 2,998,893 | 13 minutes 58 seconds | 12 minutes 57 seconds | 12 minutes 2 seconds | 0.06 seconds | -| v1 | 10000 | 3,036,441 | 17 minutes 47 seconds | 13 minutes 35 seconds | 12 minutes 13 seconds | 0.06 seconds | -| v2 | 10000 | 3,036,172 | 1 minutes 16 seconds | 13 minutes 59 seconds | 12 minutes 25 seconds | 0.06 seconds | +1. _Noir_: 0.32.0 -## Noir v0.32.0 Barrettenberg v0.46.1 +2. _Barrettenberg_: 0.46.1 -_Machine_: `20 Cores, 144 GB RAM` +Ultra Honk: -_Maximum RAM consumption_: `123 GB` +1. _Noir_: 0.33.0 + +2. _Barrettenberg_: 0.47.1 + +--- -## Table (Ultra Plonk) - -| Version | Message Length | Constraints | Execution Time | Proving Time | Writing VK Time | Verifying Time | -|---------|----------------|-------------|--------------------|--------------------|--------------------|----------------| -| v1 | 5 | 2,998,712 | 15 minute 59 seconds | 53 minutes 15 seconds | 37 minutes 19 seconds | 0.1 seconds | -| v2 | 5 | 2,998,520 | 18 minutes 32 seconds | 58 minutes 42 seconds | 36 minutes 25 seconds | 0.1 seconds | -| v1 | 32 | 2,998,905 | 17 minutes 34 seconds | 53 minutes 38 seconds | 36 minutes 43 seconds | 0.11 seconds | -| v2 | 32 | 2,998,636 | 17 minutes 9 seconds | 50 minutes 17 seconds | 38 minutes 59 seconds | 0.14 seconds | -| v1 | 100 | 2,999,162 | 16 minutes 49 seconds | 24 minutes 9 seconds | 22 minutes 58 seconds | 0.06 seconds | -| v2 | 100 | 2,998,893 | 16 minutes 28 seconds | 30 minutes 11 seconds | 25 minutes 14 seconds | 0.07 seconds | -| v1 | 10000 | 3,036,441 | 23 minutes 55 seconds | 38 minutes 18 seconds | 32 minutes 19 seconds | 0.08 seconds | -| v2 | 10000 | 3,036,172 | 20 minutes 35 seconds | 28 minutes 46 seconds | 30 minutes 40 seconds | 0.07 seconds | +| Version | Message Length | Constraints | Execution Time | Proving Ultra Plonk Time | Writing VK Ultra Plonk Time | Verifying Ultra Plonk Time | Proving Ultra Honk Time | Writing VK Ultra Honk Time | Verifying Ultra Honk Time | +|---------|----------------|-------------|----------------------|--------------------------|-----------------------------|----------------------------|-------------------------|----------------------------|---------------------------| +| v1 | 5 | 2,998,712 | 15 minutes 59 seconds | 53 minutes 15 seconds | 37 minutes 19 seconds | 0.1 seconds | 13 minutes 23 seconds | 12 minutes 3 seconds | 0.06 seconds | +| v2 | 5 | 2,998,520 | 18 minutes 32 seconds | 58 minutes 42 seconds | 36 minutes 25 seconds | 0.1 seconds | 13 minutes 9 seconds | 12 minutes 14 seconds | 0.06 seconds | +| v1 | 32 | 2,998,905 | 17 minutes 34 seconds | 53 minutes 38 seconds | 36 minutes 43 seconds | 0.11 seconds | 13 minutes 3 seconds | 11 minutes 44 seconds | 0.06 seconds | +| v2 | 32 | 2,998,636 | 17 minutes 9 seconds | 50 minutes 17 seconds | 38 minutes 59 seconds | 0.14 seconds | 12 minutes 55 seconds | 11 minutes 48 seconds | 0.06 seconds | +| v1 | 100 | 2,999,162 | 16 minutes 49 seconds | 24 minutes 9 seconds | 22 minutes 58 seconds | 0.06 seconds | 13 minutes 4 seconds | 12 minutes 30 seconds | 0.06 seconds | +| v2 | 100 | 2,998,893 | 16 minutes 28 seconds | 30 minutes 11 seconds | 25 minutes 14 seconds | 0.07 seconds | 12 minutes 57 seconds | 12 minutes 2 seconds | 0.06 seconds | +| v1 | 10,000 | 3,036,441 | 23 minutes 55 seconds | 38 minutes 18 seconds | 32 minutes 19 seconds | 0.08 seconds | 13 minutes 35 seconds | 12 minutes 13 seconds | 0.06 seconds | +| v2 | 10,000 | 3,036,172 | 17 minutes 47 seconds | 28 minutes 46 seconds | 30 minutes 40 seconds | 0.07 seconds | 13 minutes 59 seconds | 12 minutes 25 seconds | 0.06 seconds | diff --git a/README.md b/README.md index ed77199..e70bb6c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Plume is needed to confirm your identity without disclosing your private data, i ```toml [dependencies] -plume = { git = "https://github.com/distributed-lab/noir-plume", tag = "v0.1.2", directory = "crates/plume"} +plume = { git = "https://github.com/distributed-lab/noir-plume", tag = "v1.0.0", directory = "crates/plume"} ``` ### Use in your `Noir` code as following diff --git a/crates/use_v1/Prover.toml b/crates/use_v1/Prover.toml index ae55478..6e259fb 100644 --- a/crates/use_v1/Prover.toml +++ b/crates/use_v1/Prover.toml @@ -1,5 +1,5 @@ -c = ["216", "118", "145", "136", "91", "4", "222", "116", "104", "12", "106", "187", "190", "242", "23", "160", "145", "79", "64", "36", "137", "68", "67", "40", "36", "148", "218", "32", "143", "73", "204", "117"] -msg = ["78", "144", "86", "203", "136", "176", "142", "202", "13", "231", "136", "140", "230", "246", "201", "84", "37", "14", "86", "181", "47", "135", "224", "160", "104", "238", "248", "175", "110", "33", "167", "28"] -nullifier = [["148", "173", "27", "47", "88", "231", "178", "194", "118", "60", "241", "202", "54", "249", "171", "223", "125", "20", "188", "3", "146", "107", "75", "52", "46", "250", "78", "248", "107", "106", "215", "130"], ["13", "64", "28", "120", "252", "184", "118", "45", "251", "190", "134", "128", "88", "154", "188", "127", "222", "247", "124", "180", "52", "155", "36", "216", "160", "165", "157", "100", "139", "252", "148", "241"]] -pk = [["61", "255", "45", "182", "240", "139", "216", "171", "63", "196", "181", "37", "57", "74", "197", "53", "116", "27", "185", "236", "208", "115", "25", "185", "218", "227", "60", "193", "3", "246", "244", "93"], ["52", "22", "83", "206", "10", "220", "93", "188", "208", "32", "144", "236", "29", "103", "110", "222", "229", "48", "72", "213", "41", "234", "47", "10", "148", "104", "28", "215", "230", "20", "42", "118"]] -s = ["31", "240", "219", "166", "219", "231", "17", "13", "124", "15", "221", "231", "83", "171", "188", "50", "208", "0", "26", "38", "200", "138", "134", "86", "114", "207", "166", "21", "172", "173", "22", "12"] +c = ["227", "54", "1", "103", "25", "8", "51", "200", "42", "48", "137", "131", "235", "125", "242", "84", "183", "97", "91", "147", "220", "212", "6", "137", "78", "205", "98", "4", "86", "38", "54", "0"] +msg = ["29", "5", "107", "75", "5", "64", "64", "196", "205", "159", "210", "19", "165", "95", "8", "250", "133", "94", "90", "98", "219", "60", "28", "215", "70", "41", "44", "146", "242", "43", "198", "82"] +nullifier = [["148", "153", "112", "14", "122", "145", "63", "128", "185", "170", "56", "24", "113", "189", "154", "203", "80", "119", "188", "94", "153", "229", "174", "119", "60", "103", "17", "179", "203", "130", "97", "157"], ["40", "9", "144", "147", "243", "150", "242", "114", "230", "116", "22", "119", "211", "163", "190", "133", "255", "5", "26", "63", "231", "98", "21", "149", "47", "116", "11", "16", "0", "160", "249", "177"]] +pk = [["74", "87", "180", "65", "150", "174", "139", "211", "92", "91", "219", "12", "66", "123", "211", "196", "82", "123", "11", "201", "82", "63", "59", "101", "9", "136", "189", "60", "111", "131", "167", "113"], ["95", "246", "95", "58", "40", "214", "39", "190", "191", "225", "9", "154", "191", "88", "71", "12", "143", "159", "146", "203", "119", "229", "206", "61", "57", "139", "82", "81", "56", "91", "104", "9"]] +s = ["245", "69", "103", "166", "190", "206", "6", "13", "60", "152", "149", "2", "133", "244", "121", "126", "169", "52", "91", "42", "38", "88", "175", "215", "43", "26", "64", "111", "66", "46", "171", "76"] diff --git a/crates/use_v2/Prover.toml b/crates/use_v2/Prover.toml index ea51f9b..aa9ea0c 100644 --- a/crates/use_v2/Prover.toml +++ b/crates/use_v2/Prover.toml @@ -1,5 +1,5 @@ -c = ["134", "240", "195", "22", "204", "198", "89", "57", "45", "204", "229", "224", "180", "36", "31", "83", "43", "157", "50", "199", "9", "72", "180", "141", "183", "98", "22", "88", "85", "111", "196", "95"] -msg = ["62", "9", "128", "210", "216", "31", "212", "145", "212", "204", "176", "89", "122", "123", "17", "11", "231", "171", "174", "211", "39", "82", "205", "229", "119", "125", "179", "74", "131", "66", "112", "69"] -nullifier = [["25", "148", "127", "98", "237", "6", "156", "138", "203", "120", "246", "140", "212", "59", "19", "136", "233", "162", "56", "144", "40", "31", "64", "159", "91", "62", "89", "88", "78", "190", "72", "252"], ["21", "32", "121", "57", "220", "94", "234", "215", "154", "206", "142", "118", "163", "161", "189", "61", "162", "175", "118", "173", "98", "67", "189", "118", "10", "158", "16", "128", "246", "63", "84", "222"]] -pk = [["22", "37", "199", "63", "92", "79", "168", "124", "56", "245", "179", "63", "36", "245", "105", "148", "254", "118", "69", "129", "135", "146", "226", "240", "104", "152", "215", "230", "190", "228", "63", "181"], ["43", "75", "38", "134", "210", "182", "69", "102", "199", "29", "243", "155", "87", "8", "16", "84", "188", "254", "2", "212", "227", "89", "252", "117", "195", "95", "242", "111", "193", "198", "165", "85"]] -s = ["240", "43", "180", "90", "190", "52", "21", "88", "231", "208", "113", "202", "39", "100", "104", "70", "13", "194", "197", "35", "241", "65", "143", "214", "4", "233", "73", "70", "198", "153", "201", "211"] +c = ["104", "248", "246", "119", "59", "33", "11", "250", "226", "154", "52", "163", "81", "47", "252", "165", "124", "124", "136", "190", "183", "193", "191", "40", "107", "58", "242", "41", "144", "100", "71", "197"] +msg = ["246", "82", "123", "249", "124", "205", "115", "211", "15", "203", "229", "240", "217", "168", "102", "129", "91", "194", "66", "135", "169", "175", "197", "223", "208", "108", "97", "133", "154", "194", "189", "240"] +nullifier = [["148", "120", "47", "67", "28", "148", "29", "55", "206", "42", "130", "59", "244", "6", "123", "100", "26", "38", "35", "43", "43", "207", "233", "228", "55", "83", "0", "92", "34", "3", "74", "23"], ["207", "234", "0", "23", "58", "234", "120", "255", "249", "250", "35", "96", "183", "9", "111", "51", "36", "249", "146", "193", "23", "199", "96", "86", "124", "1", "25", "118", "48", "125", "7", "237"]] +pk = [["127", "213", "162", "142", "77", "136", "118", "158", "181", "20", "125", "24", "200", "31", "2", "153", "162", "237", "20", "184", "57", "99", "245", "26", "186", "88", "207", "7", "21", "255", "47", "180"], ["128", "96", "141", "137", "202", "88", "234", "180", "131", "95", "105", "241", "10", "250", "127", "229", "70", "112", "253", "183", "70", "25", "109", "69", "129", "168", "48", "121", "175", "96", "114", "27"]] +s = ["202", "63", "235", "77", "204", "141", "92", "75", "164", "143", "147", "24", "156", "200", "97", "58", "118", "207", "194", "152", "255", "119", "5", "129", "9", "72", "48", "254", "135", "97", "245", "33"]