Skip to content

Commit 9df97b1

Browse files
committed
fix both libgmp and num-bigin builds
1 parent ea0e742 commit 9df97b1

File tree

4 files changed

+109
-62
lines changed

4 files changed

+109
-62
lines changed

src/more_ops.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ pub fn op_div_impl(a: &mut Allocator, input: NodePtr, mempool: bool) -> Response
436436

437437
// this is to preserve a buggy behavior from the initial implementation
438438
// of this operator.
439-
if q == -1 && r != 0 {
439+
if q.equal(-1) && r.not_equal(0) {
440440
q += 1;
441441
}
442442
let q1 = ptr_from_number(a, &q)?;
@@ -807,7 +807,7 @@ pub fn op_softfork(a: &mut Allocator, input: NodePtr, max_cost: Cost) -> Respons
807807
Some((p1, _)) => {
808808
let n: Number = Number::from_u8(int_atom(&p1, "softfork")?);
809809
if n.sign() == Sign::Plus {
810-
if n > max_cost {
810+
if n.greater_than(max_cost) {
811811
return err(a.null(), "cost exceeded");
812812
}
813813
let cost: Cost = n.to_u64();

src/number.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ pub use num_bigint::Sign;
88

99
use crate::allocator::{Allocator, NodePtr};
1010
use crate::reduction::EvalErr;
11+
use crate::number_traits::NumberTraits;
1112

1213
pub fn ptr_from_number(allocator: &mut Allocator, item: &Number) -> Result<NodePtr, EvalErr> {
13-
let bytes: Vec<u8> = item.to_signed_bytes_be();
14+
let bytes: Vec<u8> = item.to_signed_bytes();
1415
allocator.new_atom(bytes.as_slice())
1516
}
1617

1718
#[cfg(test)]
1819
#[cfg(feature = "num-bigint")]
1920
impl crate::number_traits::TestNumberTraits for Number {
20-
fn from_str_radix(mut s: &str, radix: i32) -> Number {
21+
fn from_str_radix(s: &str, radix: i32) -> Number {
2122
num_traits::Num::from_str_radix(s, radix as u32).unwrap()
2223
}
2324
}
@@ -29,6 +30,19 @@ impl crate::number_traits::NumberTraits for Number {
2930
i.into()
3031
}
3132

33+
fn to_signed_bytes(&self) -> Vec<u8> {
34+
let mut ret = self.to_signed_bytes_be();
35+
36+
// make number minimal by removing leading zeros
37+
while (!ret.is_empty()) && (ret[0] == 0) {
38+
if ret.len() > 1 && (ret[1] & 0x80 == 0x80) {
39+
break;
40+
}
41+
ret.remove(0);
42+
}
43+
ret
44+
}
45+
3246
fn zero() -> Number {
3347
<Number as num_traits::Zero>::zero()
3448
}
@@ -42,17 +56,30 @@ impl crate::number_traits::NumberTraits for Number {
4256
}
4357
}
4458

45-
fn to_u64(n: &Number) -> u64 {
46-
n.into()
59+
fn to_u64(&self) -> u64 {
60+
use std::convert::TryFrom;
61+
TryFrom::try_from(self).unwrap()
4762
}
4863

4964
fn div_mod_floor(&self, denominator: &Number) -> (Number, Number) {
50-
self.div_mod_floor(denominator)
65+
num_integer::Integer::div_mod_floor(self, denominator)
5166
}
5267

5368
fn mod_floor(&self, denominator: &Number) -> Number {
5469
num_integer::Integer::mod_floor(&self, denominator)
5570
}
71+
72+
fn equal(&self, other: i64) -> bool {
73+
self == &Number::from(other)
74+
}
75+
76+
fn not_equal(&self, other: i64) -> bool {
77+
self != &Number::from(other)
78+
}
79+
80+
fn greater_than(&self, other: u64) -> bool {
81+
self > &Number::from(other)
82+
}
5683
}
5784

5885
#[test]

src/number_gmp.rs

Lines changed: 70 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,50 @@ impl NumberTraits for Number {
6060
ret
6161
}
6262

63+
fn to_signed_bytes(&self) -> Vec<u8> {
64+
let size = (self.bits() + 7) / 8;
65+
let mut ret: Vec<u8> = Vec::new();
66+
if size == 0 {
67+
return ret;
68+
}
69+
ret.resize(size + 1, 0);
70+
let sign = self.sign();
71+
let mut out_size: usize = size;
72+
unsafe {
73+
gmp::mpz_export(
74+
ret.as_mut_slice()[1..].as_mut_ptr() as *mut c_void,
75+
&mut out_size,
76+
1,
77+
1,
78+
0,
79+
0,
80+
&self.v,
81+
);
82+
}
83+
// apparently mpz_export prints 0 bytes to the buffer if the value is 0
84+
// hence the special case in the assert below.
85+
assert!(out_size == ret.len() - 1);
86+
if sign == Sign::Minus {
87+
// If the value is negative, we need to convert it to two's
88+
// complement. We can't do that in-place.
89+
let mut carry = true;
90+
for digit in &mut ret.iter_mut().rev() {
91+
let res = (!*digit).overflowing_add(carry as u8);
92+
*digit = res.0;
93+
carry = res.1;
94+
}
95+
assert!(!carry);
96+
assert!(ret[0] & 0x80 != 0);
97+
if (ret[1] & 0x80) != 0 {
98+
ret.remove(0);
99+
}
100+
} else if ret[1] & 0x80 == 0 {
101+
ret.remove(0);
102+
}
103+
ret
104+
}
105+
106+
63107
fn zero() -> Number {
64108
let mut v = MaybeUninit::<gmp::mpz_t>::uninit();
65109
unsafe {
@@ -74,8 +118,8 @@ impl NumberTraits for Number {
74118
Number::from_signed_bytes_be(v)
75119
}
76120

77-
fn to_u64(n: &Number) -> u64 {
78-
n.into()
121+
fn to_u64(&self) -> u64 {
122+
u64::from(self)
79123
}
80124

81125
// returns the quotient and remained, from dividing self with denominator
@@ -95,6 +139,18 @@ impl NumberTraits for Number {
95139
}
96140
r
97141
}
142+
143+
fn equal(&self, other: i64) -> bool {
144+
self == &other
145+
}
146+
147+
fn not_equal(&self, other: i64) -> bool {
148+
self != &other
149+
}
150+
151+
fn greater_than(&self, other: u64) -> bool {
152+
self > &other
153+
}
98154
}
99155

100156
impl Number {
@@ -128,49 +184,6 @@ impl Number {
128184
ret
129185
}
130186

131-
pub fn to_signed_bytes_be(&self) -> Vec<u8> {
132-
let size = (self.bits() + 7) / 8;
133-
let mut ret: Vec<u8> = Vec::new();
134-
if size == 0 {
135-
return ret;
136-
}
137-
ret.resize(size + 1, 0);
138-
let sign = self.sign();
139-
let mut out_size: usize = size;
140-
unsafe {
141-
gmp::mpz_export(
142-
ret.as_mut_slice()[1..].as_mut_ptr() as *mut c_void,
143-
&mut out_size,
144-
1,
145-
1,
146-
0,
147-
0,
148-
&self.v,
149-
);
150-
}
151-
// apparently mpz_export prints 0 bytes to the buffer if the value is 0
152-
// hence the special case in the assert below.
153-
assert!(out_size == ret.len() - 1);
154-
if sign == Sign::Minus {
155-
// If the value is negative, we need to convert it to two's
156-
// complement. We can't do that in-place.
157-
let mut carry = true;
158-
for digit in &mut ret.iter_mut().rev() {
159-
let res = (!*digit).overflowing_add(carry as u8);
160-
*digit = res.0;
161-
carry = res.1;
162-
}
163-
assert!(!carry);
164-
assert!(ret[0] & 0x80 != 0);
165-
if (ret[1] & 0x80) != 0 {
166-
ret.remove(0);
167-
}
168-
} else if ret[1] & 0x80 == 0 {
169-
ret.remove(0);
170-
}
171-
ret
172-
}
173-
174187
pub fn to_bytes_le(&self) -> (Sign, Vec<u8>) {
175188
let sgn = self.sign();
176189

@@ -345,8 +358,8 @@ impl From<usize> for Number {
345358
}
346359
}
347360

348-
impl From<Number> for u64 {
349-
fn from(n: Number) -> u64 {
361+
impl From<&Number> for u64 {
362+
fn from(n: &Number) -> u64 {
350363
unsafe {
351364
assert!(gmp::mpz_sizeinbase(&n.v, 2) <= 64);
352365
assert!(gmp::mpz_cmp_si(&n.v, 0) >= 0);
@@ -355,8 +368,8 @@ impl From<Number> for u64 {
355368
}
356369
}
357370

358-
impl From<Number> for i64 {
359-
fn from(n: Number) -> i64 {
371+
impl From<&Number> for i64 {
372+
fn from(n: &Number) -> i64 {
360373
unsafe {
361374
assert!(gmp::mpz_sizeinbase(&n.v, 2) <= 64);
362375
gmp::mpz_get_si(&n.v)
@@ -456,6 +469,9 @@ impl From<&Node<'_>> for Option<Number> {
456469
}
457470
}
458471

472+
// TODO: move all tests to number.rs so we can test both the GMP and num-bigint
473+
// versions
474+
459475
// ==== TESTS ====
460476

461477
#[cfg(test)]
@@ -489,7 +505,7 @@ fn roundtrip_bytes(b: &[u8]) {
489505
assert!(num.sign() == Sign::Plus);
490506
}
491507

492-
let round_trip = num.to_signed_bytes_be();
508+
let round_trip = num.to_signed_bytes();
493509

494510
assert_eq!(round_trip, b);
495511

@@ -516,7 +532,7 @@ fn roundtrip_bytes(b: &[u8]) {
516532
unsafe {
517533
gmp::mpz_neg(&mut negated.v, &num.v);
518534
}
519-
let magnitude = negated.to_signed_bytes_be();
535+
let magnitude = negated.to_signed_bytes();
520536
assert!(buf_le.iter().eq(magnitude.iter().rev()));
521537
}
522538
}
@@ -525,7 +541,7 @@ fn roundtrip_bytes(b: &[u8]) {
525541
{
526542
let unsigned_num = Number::from_unsigned_bytes_be(b);
527543
assert!(unsigned_num.sign() != Sign::Minus);
528-
let unsigned_round_trip = unsigned_num.to_signed_bytes_be();
544+
let unsigned_round_trip = unsigned_num.to_signed_bytes();
529545
let unsigned_round_trip = if unsigned_round_trip == &[0] {
530546
&unsigned_round_trip[1..]
531547
} else {
@@ -610,7 +626,7 @@ fn roundtrip_u64(v: u64) {
610626
assert!(num >= v - 1);
611627
}
612628

613-
let round_trip: u64 = num.into();
629+
let round_trip: u64 = (&num).into();
614630
assert_eq!(round_trip, v);
615631
}
616632

@@ -656,7 +672,7 @@ fn roundtrip_i64(v: i64) {
656672
}
657673

658674
assert!(num.bits() <= 64);
659-
let round_trip: i64 = num.into();
675+
let round_trip: i64 = (&num).into();
660676
assert_eq!(round_trip, v);
661677
}
662678

src/number_traits.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11

22
pub trait NumberTraits {
33
fn from_unsigned_bytes_be(v: &[u8]) -> Self;
4+
fn to_signed_bytes(&self) -> Vec<u8>;
45
fn zero() -> Self;
56
fn from_u8(v: &[u8]) -> Self;
6-
fn to_u64(n: &Self) -> u64;
7+
fn to_u64(&self) -> u64;
78
fn div_mod_floor(&self, denominator: &Self) -> (Self, Self) where Self: Sized;
89
fn mod_floor(&self, denominator: &Self) -> Self;
10+
fn equal(&self, other: i64) -> bool;
11+
fn not_equal(&self, other: i64) -> bool;
12+
fn greater_than(&self, other: u64) -> bool;
913
}
1014

1115
#[cfg(test)]

0 commit comments

Comments
 (0)